<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>new_wisdom.log</title>
        <link>https://velog.io/</link>
        <description>🚛 블로그 이사합니다  https://newwisdom.tistory.com/ </description>
        <lastBuildDate>Sat, 06 Mar 2021 12:16:48 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>new_wisdom.log</title>
            <url>https://images.velog.io/images/new_wisdom/profile/2d37fb6d-a3dc-45c9-8a4c-e41bf9e02985/KakaoTalk_20200609_231859735.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. new_wisdom.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/new_wisdom" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] Functional Interface]]></title>
            <link>https://velog.io/@new_wisdom/Java-Functional-Interface-%EB%B6%80%EC%88%98%EA%B8%B0</link>
            <guid>https://velog.io/@new_wisdom/Java-Functional-Interface-%EB%B6%80%EC%88%98%EA%B8%B0</guid>
            <pubDate>Sat, 06 Mar 2021 12:16:48 GMT</pubDate>
            <description><![CDATA[<h3 id="java-functional-interface"><a href="https://newwisdom.tistory.com/26">[Java] Functional Interface</a></h3>
<p>글 이사했습니당 👆</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 추상 클래스와 인터페이스의 차이]]></title>
            <link>https://velog.io/@new_wisdom/Java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@new_wisdom/Java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 05 Mar 2021 13:55:57 GMT</pubDate>
            <description><![CDATA[<h2 id="추상-클래스">추상 클래스</h2>
<p><strong>간단히 말하면...</strong>
클래스를 설계도라 하면, 추상 클래스는 <strong>미완성 설계도</strong>에 비유할 수 있다.
(여기서 클래스가 미완성이라는 것은 추상 메서드를 포함하고 있다는 의미이다.)</p>
<p>예를 들면, 같은 크기의TV라도 기능의 차이에 따라 여러 종류의 모델이 있지만
설계도 90은 동일할테니, 어느정도 틀을 갖춘 상태에서 진행하는 것이 좋다.
이때 사용할 수 있는 것이 <strong>추상 클래스</strong>이다.</p>
<h4 id="추상-메서드-">추상 메서드 ?</h4>
<p>선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다.
추상 메서드는 상속받는 클래스에 따라 달라질 수 있다.</p>
<h3 id="추상-클래스-규칙">추상 클래스 규칙</h3>
<ul>
<li>추상 클래스는 키워드 <code>abstract</code>를 붙여 표현한다.
추상 메서드를 포함하지 않은 클래스에서도 <code>abstract</code>를 붙여서 추상 클래스로 지정할 수도 있다.</li>
<li>클래스를 abstract로 지정하면 <code>new</code>를 통해 객체를 직접 생성할 수 없다.</li>
<li>메소드에 abstract를 사용할 경우 interface의 메소드와 같이 구현 부분은 없다.</li>
<li>abstract로 선언한 메소드를 자식 클래스에서 반드시 구현해야 한다. (오버라이딩)
이는 자식 클래스에서 추상 메서드를 반드시 구현하도록 강제하는 것이다.</li>
</ul>
<p>다음 예제를 보면서 추상 클래스에 대해 알아보자 !</p>
<h4 id="exmaple">Exmaple</h4>
<pre><code class="language-java">public abstract class Player {
    boolean pause;
    int currentPos;

    public Player() {
        this.pause = false;
        this.currentPos = 0;
    }
    // 지정된 위치에서 재생을 시작하는 기능 수행되도록 작성
    abstract void play(int pos);
    // 재생을 즉시 멈추는 기능을 수행하도록 작성
    abstract void stop();

    void pause() {
        if (pause) {
            pause = false;
            play(currentPos);
        } else {
            pause = true;
            stop();
        }
    }
}</code></pre>
<p>Player 추상 클래스는 
VCR이나 Audio 같은 재생이 가능한 기기의 부모 클래스가 될 수 있다.
이제 Player 추상 클래스를 상속받는 CDPlayer 클래스를 만들어보자 🔨</p>
<pre><code class="language-java">public class CDPlayer extends Player {
    @Override
    void play(int pos) {
        // 구현 생략
    }

    @Override
    void stop() {
        // 구현 생략
    }

    //CDPlayer 클래스에 추가로 정의된 멤버
    int currentTrack;

    void nextTrack() {
        currentTrack++;
        // ...
    }

    void preTrack() {
        if (currentTrack &gt; 1) {
            currentTrack--;
        }
        // ...
    }
}</code></pre>
<p>부모 클래스의 추상메서드를 CDPlayer에 맞게 오버라이딩해주고, 
CDPlayer만의 새로운 멤버들을 추가해주었다.</p>
<h2 id="인터페이스">인터페이스</h2>
<p><strong>간단히 말하면...</strong>
인터페이스는 일종의 추상 클래스로, 추상 메서드를 갖지만 
추상 클래스보다 추상화 정도가 높아
추상 클래스와 달리 몸통을 갖춘 일반 메서드, 멤버 변수를 구성원으로 가질 수 없다.
추상 클래스를 미완성 설계도라 하면, 인터페이스는 구현된 것은 아무 것도 없는, 
밑그림만 그려진 <strong>기본 설계도</strong>라고 할 수 있다.</p>
<h3 id="인터페이스-규칙">인터페이스 규칙</h3>
<ul>
<li>추상 클래스처럼 불완전한 것이기 때문에 그 자체만으로 사용되기 보다,
다른 클래스를 작성하는데 도움을 줄 목적으로 작성된다.</li>
<li>일반 메서드 또는 멤버 변수를 구성원으로 가질 수 없다.</li>
<li>모든 멤버 변수는 <code>public static final</code>이어햐 하며, 이를 생략할 수 있다.</li>
<li>모든 메서드는 <code>public abtract</code>이어야 하며, 이를 생략할 수 있다.
(단, JDK1.8부터 static 메서드와 default 메서드를 사용할 수 있다.)</li>
</ul>
<p><strong>🤔 public static final의 사용 목적 ?</strong>
인터페이스 변수는 아무 인스턴스도 존재하지 않는 시점이기 떄문에 스스로 초기화 될 권한이 없다.
때문에 <code>public static final</code>를 사용해 구현 객체의 같은 상태를 보장한다.</p>
<h3 id="인터페이스의-다중-상속">인터페이스의 다중 상속</h3>
<p>인터페이스는 인터페이스로부터만 상속받을 수 있으며,
클래스와 달리 다중상속을 받는 것이 가능하다.</p>
<pre><code class="language-java">public interface Movable {
    void move(int x, int y);
}

interface Attackable {
    void attack(Unit u);
}

interface Fightable extends Movable, Attackable {
}</code></pre>
<p>클래스의 상속과 마찬가지로 자식 인터페이스는 부모 인터페이스에 정의된 멤버 모두 상속받는다.</p>
<p><strong>인터페이스가 다중 상속이 가능한 이유는?</strong>
인터페이스는 abstract 메소드만을 가지고 있는데,
이를 상속할 경우 상속하는 클래스에서 무조건 그 메서드를 구현해주어야 하는데,
이 경우 다중 상속하고 있는 인터페이스들에 동일한 메서드가 존재한다 하더라도,
그 내부 구현은 정의되지 않았으니 문제될 것이 없기 때문이 아닐까 한다.</p>
<p>그런데 이제 인터페이스에서 default 메서드를 구현할 수 있는데
두개의 인터페이스를 다중 상속하는 경우, 
이 default 메소드가 중복이 되면 어떻게 되는거지?</p>
<p>이 질문에 대한 답을 테스트 해보았다.
<img src="https://images.velog.io/images/new_wisdom/post/3bff8105-2d84-4583-ad1b-e208b362f524/image.png" alt=""></p>
<p>동일한 <code>printStatic()</code> 을 가진 인터페이스 C와 B를 상속하는 
인터페이스 A는 <code>printStatic()</code>를 무조건 오버라이딩하게 되어 있었다...
만약 중복 메서드가 없을 경우 오버라이딩을 하지 않아도 컴파일 에러가 나지 않는다.</p>
<h4 id="🍯-tip">🍯 Tip</h4>
<p>인터페이스 명은 대부분 &quot;<del>을 할 수 있는&quot;의 의미인 <code>able</code>로 끝나는 것들이 많다고 한다.
그 이유는 어떤 기능 또는 행위를 하는데 필요한 메서드를 제공한다는 의미를 강조하기 위해서다.
때문에 그 인터페이스를 구현하는 클래스는 &quot;</del>를 할 수 있는&quot; 능력을 갖추었다는 의미이기도 하다.</p>
<h2 id="추상-클래스-vs-인터페이스">추상 클래스 VS 인터페이스</h2>
<h4 id="공통점-">공통점 ?</h4>
<p>먼저 추상 클래스와 인터페이스의 공통점을 찾아보자. 
추상 클래스와 인터페이스 둘 다 <strong>가지고 있는 추상 메서드를 구현하도록 강제한다.</strong>
또 <strong>인스턴스화가 불가능</strong>하다.</p>
<p>그렇다면 추상 클래스 안에 원하는 것만 추상 메서드를 여러개 두거나,
전부 추상 메서드로 만들면 되어 추상 클래스가 인터페이스 역할을 할 수 있다.
만약 모든 클래스가 인터페이스만 사용해서 구현한다면,
모든 클래스에서 공통으로 필요한 기능들은 각각 오버라이딩 하게 되니 코드의 중복이 발생한다.
때문에 이 공통으로 필요한 기능들을 부모 클래스에서 일반 메서드로 구현한
추상클래스를 상속 받아 자식 클래스에서 사용할 수 있도록 하면 될거같은데...
<strong>왜 인터페이스는 왜 필요한걸까? 🤔</strong></p>
<h3 id="접근자">접근자</h3>
<p><strong>인터페이스</strong>에서 모든 변수는 <code>public static final</code>, 
모든 메소드는 <code>public abstract</code>이다.
하지만 <strong>추상 클래스</strong>에서는 <code>static</code>이나 <code>final</code>이 아닌 필드를 가질 수 있고, 
<code>public, protected, private</code> 모두 가질 수 있다.</p>
<p>개인적인 생각으로는 인터페이스만을 구현하면 <code>public static final</code>만을 사용해
구현 객체의 같은 상태를 공유할수 밖에 없는데,
추상 클래스는 <code>static</code>이나 <code>final</code>이 아닌 필드또한 가질 수 있기 때문에 
추상 클래스를  상속 받은 객체들이 같은 상태를 가지고 있을 수 있다.</p>
<h3 id="다중-상속-여부">다중 상속 여부</h3>
<p><strong>인터페이스</strong>를 구현하는 클래스는 다른 여러개 인터페이스를 함께 구현할 수 있다.
하지만 자바에서는 다중 상속을 지원하지 않기 때문에 여러 추상 클래스를 상속할 수 없다.</p>
<h3 id="사용-의도">사용 의도</h3>
<p>물론 다중 상속 여부의 차이는 있지만 이것이 포인트가 아니라,
이에 따른 사용 목적이 다르다는 것에 포인트를 맞춰보자.
위에서 말한 다중 상속 여부에 따라 추상 클래스와 인터페이스의 사용 의도 또한 다르다.</p>
<p><strong>추상 클래스</strong>는 이를 상속할 각 객체들의 공통점을 찾아 추상화시켜 놓은 것으로,
상속 관계를 타고 올라갔을 때 같은 부모 클래스를 상속하며 
부모 클래스가 가진 기능들을 구현해야할 경우 사용한다.</p>
<p><strong>인터페이스</strong>는 상속 관계를 타고 올라갔을 때 
다른 조상 클래스를 상속하더라도, 같은 기능이 필요할 경우 사용한다.
클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용한다.</p>
<h4 id="exmaple-1">Exmaple</h4>
<p>아래와 같은 관계를 갖는 예제를 살펴본다.
<img src="https://images.velog.io/images/new_wisdom/post/af9d99ef-28f2-483f-a261-161cb979fb4a/image.png" alt="">
제일 부모 클래스인 Creature은 생물에 대한 Abstract Class이다.
각 생물은 구분에 따라 Animal 또는 Plant를 상속한다.
그리고 각각이 할 수 있는 추가적인 기능들을 인터페이스로 구현했다.</p>
<p>Animal을 상속받는 Amazzi(나^^), Dog, Cat은 Plant와 다르게
bark(짖다) 할 수 있으니 Barkable 인터페이스를 구현하였다.</p>
<p>여기서 눈여겨 볼 것은 바로 Eatable인데, 
Eatable 인터페이스는 현재 상속 관계가 다른 Amazzi(나^^), Dog, Cat, FlyHellPlant에게
공통적인 기능인 Eat 기능을 인터페이스를 사용함으로 같은 기능을 구현하도록 강제하고 있다.</p>
<p>그러면 결국 이 4가지 클래스 모두 생물 클래스를 상속하고 있는데,
생물 클래스에 eat이라는 추상 메서드를 만들면 안되는가?라고 생각할 수 있지만
Plant를 상속받은 Rose는 eat 메소드를 가질 수 없다.</p>
<p>그러면 어떻게하지 🤷‍♀️</p>
<p>이때 바로 인터페이스로 따로 선언을 해주어 각각 eat을 할 수 있는 
클래스에 implements해주어 만들어 주면 <strong>가독성이 올라가며 유지보수 또한 쉬워진다.</strong></p>
<h3 id="각각의-적절한-사용-케이스-정리">각각의 적절한 사용 케이스 정리</h3>
<h4 id="추상-클래스-1">추상 클래스</h4>
<ul>
<li>관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우</li>
<li>추상 클래스를 상속 받을 클래스들이 공통으로 가지는 메소드와 필드가 많거나, 
public이외의 접근자(protected, private) 선언이 필요한 경우</li>
<li>non-static, non-final 필드 선언이 필요한 경우 (각 인스턴스에서 상태 변경을 위한 메소드가 필요한 경우)</li>
</ul>
<h4 id="인터페이스-1">인터페이스</h4>
<ul>
<li>서로 관련성이 없는 클래스들이 인터페이스를 구현하게 되는 경우. 
ex) Comparable, Cloneable 인터페이스는 여러 클래스들에서 구현되는데, 구현클래스들 간에 관련성이 없다.</li>
<li>특정 데이터 타입의 행동을 명시하고 싶은데, 어디서 그 행동이 구현되는지는 신경쓰지 않는 경우.</li>
<li>다중상속을 허용하고 싶은 경우</li>
</ul>
<h2 id="참고-자료">참고 자료</h2>
<ul>
<li><a href="https://myjamong.tistory.com/150">[JAVA] 추상클래스 VS 인터페이스 왜 사용할까? 차이점, 예제로 확인 :: 마이자몽</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 상속에 대하여]]></title>
            <link>https://velog.io/@new_wisdom/0302</link>
            <guid>https://velog.io/@new_wisdom/0302</guid>
            <pubDate>Wed, 03 Mar 2021 15:02:22 GMT</pubDate>
            <description><![CDATA[<p>강의시간에 배운 상속 개념에 추가로 공부한 내용을 정리해본다 ✍️</p>
<h2 id="상속">상속</h2>
<p><strong>먼저 상속이란 ?</strong>
기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.
예제를 보명서 상속의 필요성을 파악해보자 !</p>
<h3 id="example">Example</h3>
<p>카페에서 커피와 차를 판매한다.
커피와 차를 준비하는 과정을 살펴보자.</p>
<h4 id="커피">커피</h4>
<ul>
<li>물을 끓인다.</li>
<li>커피머신으로 커피를 내린다.</li>
<li>컵에 붓는다.</li>
<li>설탕과 우유를 추가한다.<h4 id="차">차</h4>
</li>
<li>물을 끓인다.</li>
<li>차 티백을 담근다.</li>
<li>컵에 붓는다.</li>
<li>레몬을 추가한다.</li>
</ul>
<p>그렇다면 각각의 과정들을 코드로 구현해본다.</p>
<pre><code class="language-java">public class Coffee {
    void prepareRecipe() {
        boilWater();
        brewCoffeeMachine();
        pourInCup();
        addSugarAndMilk();
    }

    public void boilWater() {
        System.out.println(&quot;물을 끓인다.&quot;);
    }

    public void brewCoffeeMachine() {
        System.out.println(&quot;커피머신으로 커피를 내린다.&quot;);
    }

    public void pourInCup() {
        System.out.println(&quot;컵에 붓는다.&quot;);
    }

    public void addSugarAndMilk() {
        System.out.println(&quot;설탕과 우유를 추가한다.&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class Tea {
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    public void boilWater() {
        System.out.println(&quot;물을 끓인다.&quot;);
    }

    public void steepTeaBag() {
        System.out.println(&quot;티백을 담근다.&quot;);
    }

    public void pourInCup() {
        System.out.println(&quot;컵에 붓는다.&quot;);
    }

    public void addLemon() {
        System.out.println(&quot;레몬을 추가한다.&quot;);
    }
}</code></pre>
<p>Coffee 클래스와 Tea 클래스를 비교해보면 이상한 점을 느낄 수 있다.
<code>prepareRecipe()</code>, <code>boilWater()</code>, <code>pourInCup()</code> 
이 세가지 메소드는 공통된 기능을 하지 않는가??</p>
<p>그렇다면 &quot;이 중복된 부분을 어떻게 제거하느냐?&quot;에 대한 해답으로
바로 <strong>상속</strong>이 나온다.</p>
<p>그렇다면 두 클래스에서 공통된 부분을 추출하여 부모 클래스를 만들어본다.</p>
<pre><code class="language-java">public class Beverage {
    protected void boilWater() {
        System.out.println(&quot;물을 끓인다.&quot;);
    }

    protected void pourInCup() {
        System.out.println(&quot;컵에 붓는다.&quot;);
    }
}</code></pre>
<p>공통된 기능을 묶은 부모 클래스인 Beverage를 상속 받는 각각의 클래스를 만들어본다.</p>
<pre><code class="language-java">public class Coffee extends Beverage {
    void prepareRecipe() {
        boilWater();
        brewCoffeeMachine();
        pourInCup();
        addSugarAndMilk();
    }

    public void brewCoffeeMachine() {
        System.out.println(&quot;필터를 활용해 커피를 내린다.&quot;);
    }

    public void addSugarAndMilk() {
        System.out.println(&quot;설탕과 우유를 추가한다.&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class Tea extends Beverage {
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    public void steepTeaBag() {
        System.out.println(&quot;티백을 담근다.&quot;);
    }

    public void addLemon() {
        System.out.println(&quot;레몬을 추가한다.&quot;);
    }
}</code></pre>
<h3 id="extends">extends</h3>
<p>이렇게 상속은 <code>extends</code> 키워드로 이루어 진다.
상속을 할 경우 멤버 필드와 메소드를 하위 클래스에서 그대로 상속하게 되는데,
키워드의 의미대로 자식 클래스가 조상 클래스를 확장하는 의미로 해석할 수 있다.
<strong>여기서 주의점 !</strong></p>
<ul>
<li>생성자와 초기화 블럭은 상속되지 않는다. 멤버만 상속된다.</li>
<li>자식 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.</li>
<li>private, default는 상속되지 않는다기 보다는 상속은 받지만 자식 클래스로부터의 접근이 제한된다.</li>
<li>자바에서는 다중 상속을 지원하지 않는다.</li>
</ul>
<h2 id="오버라이딩">오버라이딩</h2>
<p>조상 클래스로부터 상속 받은 메서드의 내용을 변결하는 것
자식 클래스에서 부모 클래스 메서드를 맞게 변경하는 경우 오버라이딩을 한다.</p>
<h3 id="오버라이딩의-조건">오버라이딩의 조건</h3>
<p>자식 클래스의 메소드에서 부모 클래스의 메소드와 다음 조건들이 같아야 한다.</p>
<ul>
<li>메소드 명</li>
<li>매개변수</li>
<li>반환타입<h3 id="오버라이딩-주의점">오버라이딩 주의점</h3>
</li>
<li>접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.</li>
<li>예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.</li>
<li>인스턴스메서드를 static 메서드, 또는 그 반대로 변경할 수 없다.</li>
</ul>
<p><strong>🤔 조상 클래스에 정의된 static 메서드를 자손 클래스에서 똑같은 이름의 static 메서드로 정의할 수 있나?</strong>
가능은 하지만 각 클래스에 별개의 static 메서드를 정의한 것일 뿐 오버라이딩이 아니다.</p>
<h3 id="상속의-장점">상속의 장점</h3>
<ul>
<li>중복된 코드를 줄일 수 있다.</li>
<li>공통적 필드를 추가하거나, 수정할 때 부모 클래스에만 작업해주면 된다.</li>
</ul>
<h3 id="클래스간의-관계">클래스간의 관계</h3>
<p>상속을 통해 클래스간에 관계를 맺어주는데, 
이때 생기는 관계를 몇 가지 유형으로 나눠볼 수 있다.</p>
<h4 id="is-a-관계-is-a-relationship">is-a 관계 (is a relationship)</h4>
<p>is-a 관계는 일반적인 개념과 구체적인 개념과의 관계를 말한다.
여기서 일반적인 개념 클래스는 상위 클래스인 부모 클래스를 뜻하고,
구체적인 개념 클래스는 하위 클래스인 자식 클래스를 뜻한다.</p>
<p>말 그대로 <strong>&quot;~은 ~이다.&quot;라는 문장이 성립되어야 한다.</strong></p>
<ul>
<li>Example<pre><code class="language-java">public class Person{
String name; 
int age; 
}
</code></pre>
</li>
</ul>
<p>public class Student extends Person{
int number; 
int major; 
}</p>
<pre><code>위 예제에서는 Student 클래스가 Person 클래스를 상속받고 있다.
&quot;학생은 사람이다.&quot;처럼 이러한 관계를 is-a 관계라고 한다.

#### has-a 관계 (composition)
has-a 관계는 한 클래스가 다른 클래스를 소유한 관계이다.

말 그대로 **&quot;~은 ~을 가지고 있다.&quot;라는 문장이 성립되어야 한다.**
* Example
```java
class Circle {
    Point point;
    int r;
} 

class Point {
    int x;
    int y;
}</code></pre><p>위 예제에서는 Point 클래스를 재사용해서 Circle 클래스를 작성했다.
하나의 거대한 클래스를 작성하는 것보다 단위별로 여러 개의 클래스를 작성한 후,
이 단위 클래스들을 포함관계로 재사용하면 보다 간결하고 손쉽게 클래스를 작성할 수 있다.
또 작성된 단위 클래스들은 다른 클래스를 작성하는데 재사용될 수 있다.</p>
<p>&quot;<del>은 ~이다.&quot; 또는 &quot;</del>은 ~을 가지고 있다.&quot; 문장을 만들어보고 
더 적합한 관계를 구현하는 것이 좋다.</p>
<p>(이펙티브 자바에 &quot;상속보단 조합&quot;이라는 개념이 있던데 이 부분도 정리해보아야겠다.)</p>
<h2 id="캐스팅">캐스팅</h2>
<p><strong>🤔 캐스팅이란 ?</strong>
타입을 변환하는 것을 말하며, 형변환이라고도 한다.
기본형 변수와 같이 참조변수도 형변환이 가능한데, 상속 관계에 있는 클래스 사이에서만 가능하다.</p>
<p>이때, 기본형 참조형 변수의 형변환에서 자손 타입의 참조변수를 조상타입으로 
형변환하는 경우에는 형변환을 생략할 수 있다.</p>
<h3 id="업캐스팅">업캐스팅</h3>
<p>자식 클래스의 참조변수를 부모 클래스의 참조변수로 변환하며, 형변환 생략이 가능하다.
부모 클래스의 참조 변수가 자식 클래스로 객체화된 인스턴스를 가리킬 수 있다.
때문에 다형성을 위해 사용된다.
ex) 학생은 사람이다.</p>
<p>위에서 다뤘던 Student 예제로 확인해보자.</p>
<pre><code class="language-java">// 참조변수 student를 이용하면 number, major에 접근 가능
Student student = new Student();

// 레퍼런스 person을 이용하면 Student 객체의 멤버 중 
// 오직 Person 클래스의 멤버만 접근이 가능하다.
Person person = student;
person.name = &quot;amazzi&quot;;
person.age = 10;

// 아래 문장은 컴파일 오류가 난다.
person.number = &quot;12345678&quot;;</code></pre>
<p>이처럼 업캐스팅을 하게되면 부모 클래스의 필드, 메서드에만 접근이 가능하다.</p>
<h3 id="다운캐스팅">다운캐스팅</h3>
<p>자식 클래스의 참조변수를 자식 타입의 참조변수로 변환하며, 형변환 생략이 불가능하다.
자신의 고유한 특성을 잃은 서브 클래스의 객체를 다시 복구 시켜주는 것을 말한다. (업캐스팅 복구?)</p>
<pre><code class="language-java">// 업캐스팅 먼저
Person person = new Student();

// 다운캐스팅
Student student = (Student) person;

// Ok
student.name = &quot;amazzi&quot;;
student.number = &quot;12345678&quot;;</code></pre>
<p>꼭 업캐스팅이 먼저 선행이 되어야 한다.
만약 다음과 같은 경우는 컴파일 오류는 나지 않지만 <code>ClassCastException</code> 런타임 오류가 발생한다.</p>
<pre><code class="language-java">Student student = (Student) new Person();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코드 리뷰 정리] Level1. 로또]]></title>
            <link>https://velog.io/@new_wisdom/%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@new_wisdom/%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Mon, 01 Mar 2021 07:11:24 GMT</pubDate>
            <description><![CDATA[<h2 id="1단계-피드백">1단계 피드백</h2>
<h3 id="객체인-controller">객체인 Controller</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/c00aaeae-a114-4634-ba8b-15d91ea499f6/image.png" alt="">
LottoFactory를 인스턴스 변수로 두지 않았던 이유는 
Controller는 객체가 아니라 데이터를 가지면 안된다고 생각하고 있었다.
당연히 Domain만 객체라고 생각했었다. (모르는건 부끄러운게 아니다 🥲)</p>
<p>하지만 생각해보니 Controller도 도메인과 뷰를 이어주는 동시에, 객체를 생성하는 책임이 있다.
인스턴스 변수로 가지고 있게 된다면 getLottoTickets 메소드에서 매번 객체를 생성할 필요가 없다.</p>
<p>일단 이 코드에서 중요한 점은 어차피 지금 로또를 생성하는 책임을 컨트롤러에서 하고 있었으니
&quot;불필요한 객체 생성을 방지하도록 인스턴스 변수로만들어서 재활용하자&quot;가 목적이다.</p>
<ul>
<li><a href="https://github.com/woowacourse/java-lotto/commit/ab16861d71a72d2016ef4cd232a5cf5b5af86ac9">반영한 커밋</a><h3 id="반복되는-상수-처리">반복되는 상수 처리</h3>
<img src="https://images.velog.io/images/new_wisdom/post/acf1e691-e345-41ee-a67b-e249b23f6547/image.png" alt=""></li>
</ul>
<p><img src="https://images.velog.io/images/new_wisdom/post/3fd15906-7210-4084-bf94-32f8d9a2141a/image.png" alt="">
미션 데드라인을 맞추기 위해 좀 더 꼼꼼히 확인을 못했던 부분인데,
로또 티켓을 만드는 LottoTicketFactory에 있는 상수 값들이 LottoNumber나 LottoTicket등 여러 곳에서 중복되어 쓰이고 있었다.
또 심지어 로또의 MAX 번호는 45인데, 49까지로 입력해 놓았다 🙃
덕분에 상수값 하나라도 꼼꼼히 확인해야겠다는 깨달음을 얻었다.</p>
<p>중복되는 상수를 막으며, 각 객체가 알고 있어야 하는 값대로 상수를 두고
이를 import 해서 사용하도록 수정했다.</p>
<h4 id="lottonumber">LottoNumber</h4>
<pre><code class="language-java">public class LottoNumber implements Comparable&lt;LottoNumber&gt; {
    public static final int MIN_LOTTO_NUMBER = 1;
    public static final int MAX_LOTTO_NUMBER = 45;
    private static final Pattern NUMBER_PATTERN = Pattern.compile(&quot;^[0-9]*$&quot;);</code></pre>
<h4 id="lottoticket">LottoTicket</h4>
<pre><code class="language-java">public class LottoTicket {
    public static final int LOTTO_TICKET_SIZE = 6;</code></pre>
<h4 id="lottofactory">LottoFactory</h4>
<pre><code class="language-java">import static lotto.domain.LottoNumber.MAX_LOTTO_NUMBER;
import static lotto.domain.LottoNumber.MIN_LOTTO_NUMBER;
import static lotto.domain.LottoTicket.LOTTO_TICKET_SIZE;
import static lotto.domain.Money.LOTTO_PRICE;

public class LottoTicketFactory {
    private static final int START_INDEX = 0;</code></pre>
<ul>
<li><a href="https://github.com/woowacourse/java-lotto/commit/95988ad3982c06c1d6b105db83bd0fa9b559260a">반영한 커밋</a><h3 id="구매-금액-계산-법">구매 금액 계산 법</h3>
<img src="https://images.velog.io/images/new_wisdom/post/1c7743ed-6856-4410-809d-aa6c383c680d/image.png" alt="">
리팩토링 전 로직으로는 구매 금액을 입력 받을 때 만약 14500원이 들어오면 사용한 금액은
14장을 사는데 14000원만 들게 하고 500원이 남는 것은 예외라고 생각하지 않고 진행했다.
그런데 이 로직은 구매한 금액이 아닌 지불한 14500원으로 수익률을 계산하고 있다.
때문에 입력 금액과 구매 금액의 미일치 오류가 발생한다.</li>
</ul>
<p>피드백을 통해 lottoResult에서 구할 수 있는 티켓 개수와 상수 변수인 로또의 구매장수로
지불 금액을 구할 수 있음을 깨닫고 <code>showResult()</code> 에서 <code>money</code>를 매개변수로 받을 필요가 없음을 깨달았다.</p>
<p>덕분에 money와의 연관관계를 하나 끊을 수 있고, 
수익금 계산 시 입력 금액과 구매 금액 미일치로 인한 수익률 에러를 방지할 수 있다.</p>
<ul>
<li><a href="https://github.com/woowacourse/java-lotto/commit/06cf1861eab0fcd0900218e06c38024fcae2d957">반영한 커밋</a></li>
</ul>
<h3 id="prize에서의-static-메서드-사용">Prize에서의 static 메서드 사용</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/1c8c1eac-ab18-4280-b3ad-e5ab1ff285bb/image.png" alt=""></p>
<h4 id="리팩토링-전-prize">리팩토링 전 Prize</h4>
<pre><code class="language-java">    public static Prize getPrizeType(int matchCount, boolean isBonusBall) {
        if (isMatchCountEqualsPivot(matchCount) &amp;&amp; isBonusBall) {
            return SECOND_PRIZE;
        }
        return Arrays.stream(values())
                .filter(s -&gt; s.matchCount == matchCount)
                .findFirst()
                .orElse(NO_PRIZE);
    }

    private static boolean isMatchCountEqualsPivot(int matchCount) {
        return matchCount == BONUS_CHECK_PIVOT;
    }

    public static double calculatePrizeMoneySum(List&lt;Prize&gt; lottoResults, Money money) {
        Money moneySum = Money.ZERO;
        for (Prize prize : Prize.values()) {
            Money perPrizeMoneySum = prize.prizeMoney
                    .multiple(getCountByPrizeType(lottoResults, prize));
            moneySum = moneySum.plus(perPrizeMoneySum);
        }
        return moneySum.getRate(money);
    }

    public static int getCountByPrizeType(List&lt;Prize&gt; lottoResults, Prize prize) {
        return (int) lottoResults.stream()
                .filter(p -&gt; p.equals(prize))
                .count();
    }
</code></pre>
<h4 id="리팩토링-전-lottoresult">리팩토링 전 LottoResult</h4>
<pre><code class="language-java">public class LottoResult {
    private final List&lt;Prize&gt; lottoResults;

    public LottoResult(List&lt;Prize&gt; lottoResults) {
        this.lottoResults = new ArrayList&lt;&gt;(lottoResults);
    }

    public double calculateProfitRate(Money money) {
        return Prize.calculatePrizeMoneySum(lottoResults, money);
    }

    public int getCountPerPrizeType(Prize prize) {
        return Prize.getCountByPrizeType(lottoResults,prize);
    }
}</code></pre>
<p>LottoResult에서 <code>calculateProfitRate()</code>을 하기 위해  Prize의 도움을 받았다.
lottoResults가 Prize의 도움을 받지 않고 <code>List&lt;Prize&gt; lottoResults</code> 
각각의 prize에게 메시지를 보내 스스로 계산할 수 있도록 코드를 다음과 같이 수정했었다.</p>
<h4 id="lottoresult">LottoResult</h4>
<pre><code class="language-java">    public Money getTotalProfit() {
        Money totalProfit = Money.ZERO;
        for (Prize prize : lottoResults) {
            totalProfit = totalProfit.plus(prize.getPrizeMoney());
        }
        return totalProfit;
    }</code></pre>
<ul>
<li><a href="https://github.com/woowacourse/java-lotto/commit/af0f1ff2915d6420b6935e1baa9510c1030c7daf">1차 반영 커밋</a></li>
</ul>
<p>하지만 리팩토링 후에도 아직 객체 스스로 할 수 있는일들이 남아있었다.
<img src="https://images.velog.io/images/new_wisdom/post/7b50bea1-587b-415b-bc03-81942871a2a9/image.png" alt="">
<code>prize</code>별 갯수를 구하는 것도 stream을 사용해 매개변수로 들어오는 
<code>prize</code>와 비교해 값을 count 할 수 있었는데,
아직도 Prize의 static 메소드를 사용하여 Prize의 도움을 받고 있었다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/acb68cb8-5309-4c65-a040-2babdc96a770/image.png" alt=""></p>
<p>또 이때까지 로또 티켓과 당첨 티켓을 비교해 결과를 반환하는 책임을 
lottoTickets가 가지고 있었다.
곰곰히 생각해보니 로또 티켓과 당첨 티켓을 비교해 결과를 반환하는 책임은 winningLotto가 맡는 것이 더 적합하다고 판단이 되었고,
winningLotto에서 prize를 체크하도록 책임을 이동하였다.</p>
<p>최종적으로 LottoResult를 반환하는 것은 winnigLotto에서 담당하며,
또 Prize의 도움을 받지 않고 스스로 prize를 체크하도록 하였다.</p>
<h4 id="리팩토링한-winniglotto의-메소드-일부">리팩토링한 WinnigLotto의 메소드 일부</h4>
<pre><code class="language-java">public Prize matchPrize(LottoTicket lottoTicket) {
    int matchCount = getMatchingCount(lottoTicket);
    boolean isBonusNumber = isContainBonusNumber(lottoTicket);
    return Prize.findPrize(matchCount, isBonusNumber);
}

private int getMatchingCount(LottoTicket lottoTicket) {
    return (int) lottoTicket.lottoTicket().stream()
            .filter(winningTicket.lottoTicket()::contains)
            .count();
}

private boolean isContainBonusNumber(LottoTicket lottoTicket) {
    return lottoTicket.lottoTicket()
            .stream()
            .anyMatch(lottoNumber -&gt; lottoNumber.equals(bonusNumber));
}</code></pre>
<h4 id="리팩토링-후-prize에서-줄어든-static-메소드들">리팩토링 후 Prize에서 줄어든 static 메소드들</h4>
<pre><code class="language-java">public static Prize findPrize(int matchCount, boolean isBonusNumber) {
    if (isMatchCountEqualsPivot(matchCount) &amp;&amp; isBonusNumber) {
        return SECOND_PRIZE;
    }

    return Arrays.stream(values())
            .filter(s -&gt; s.matchCount == matchCount)
            .findFirst()
            .orElse(NO_PRIZE);
}

private static boolean isMatchCountEqualsPivot(int matchCount) {
    return matchCount == BONUS_CHECK_PIVOT;
}

public Money getPrizeMoney() {
    return prizeMoney;
}

public int getMatchCount() {
    return matchCount;
}</code></pre>
<ul>
<li><a href="https://github.com/woowacourse/java-lotto/commit/df62ef0a1e9ef8bf680d03556a0c44886d252c24">반영한 커밋1</a></li>
<li><a href="https://github.com/woowacourse/java-lotto/commit/e0acff81ab0893813483949504c22bd954271a46">반영한 커밋2</a></li>
</ul>
<h3 id="collectingandthen">collectingAndThen</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/40036589-2ae0-4833-a4ed-8bf372d68844/image.png" alt="">
리뷰어님께서 수정해주신 코드는 <code>collectingAndThen</code>메소드를 사용했는데,
처음보는 메소드라 찾아보니 collecting을 진행한 후 그 결과로 메소드를 호출할 수 있는 메서드 였다.
stream map을 써서 객체 하나하나를 생성하고 이를 리스트로 바꿔,
또 객체를 생성하는 나의 로직에서 이 메서드를 사용하면
좀 더 간결하게 표현할 수 있었다.
사용법을 배웠으니, 앞으로 자주 사용할 것이다 👀
또 Collections의 다양한 API를 살펴보아야겠다.</p>
<ul>
<li><a href="https://www.baeldung.com/java-8-collectors">참고</a></li>
</ul>
<h2 id="2단계-초기-리팩토링">2단계 초기 리팩토링</h2>
<p><img src="https://images.velog.io/images/new_wisdom/post/b07190ba-4871-4c44-8f25-b7c17d1da072/image.png" alt=""></p>
<h3 id="lottocount-객체-추가">LottoCount 객체 추가</h3>
<p>이번 리팩토링에서 <code>수동 로또 개수</code>를 입력 받고, 이 갯수 만큼 로또를 생성하고 출력해야했다.
원시값 포장의 의미도 담으면서 입력 받는 수동 로또 갯수에 대한 검증하고, 
이에 대한 상태와 행위를 한 곳에서 관리 하기 위해 <code>LottoCount</code> 객체를 만들게 되었다.</p>
<pre><code class="language-java">public class LottoCount {
    private final int manualCount;
    private final int autoCount;

    public LottoCount(int manualCount, int totalCount) {
        validateLottoCount(manualCount, totalCount);
        this.manualCount = manualCount;
        this.autoCount = totalCount - this.manualCount;
    }

    private void validateLottoCount(int manualCount, int totalCount) {
        if (manualCount &gt; totalCount || manualCount &lt; 0) {
            throw new IllegalArgumentException(&quot;[ERROR] 구매 가능한 로또 개수 범위가 아닙니다.&quot;);
        }
    }

    public int getManualCount() {
        return manualCount;
    }

    public int getAutoCount() {
        return autoCount;
    }
}</code></pre>
<h3 id="exception">Exception</h3>
<p>화요일 강의인 Exception이 내게는 많은 배움을 주어서, 
이번 요구사항인 사용자 입력값에 대한 예외처리를 신경썼다.
이전에는 Custom Exception을 만들어서 각 객체마다 예외 처리를 해주었으나, </p>
<ul>
<li>리팩토링 전 Custom Class<pre><code class="language-java">package lotto.exception;
</code></pre>
</li>
</ul>
<p>import lotto.view.ErrorView;</p>
<p>public class IllegalMoneyException extends IllegalArgumentException {
    public IllegalMoneyException() {
        ErrorView.printIllegalMoneyErrorMessage();
    }
}</p>
<pre><code>각 Custom Exception 클래스가 따로 처리하는 일이 없고, 
메세지도 super에게 전달하는 것이 아닌 `ErrorView`라는 객체를 통해 출력하고 있기 때문에 필요성을 못느끼게 되어 자바의 기본 예외를 사용하도록 리팩토링을 진행했다.
또 객체 단위로 묶어서 에러 메세지를 보내던 부분은 
각 예외 사항에 맞게 에러 메시지를 보내도록 수정했다.

#### LottoTicketFactory -&gt; AutoNumbersFactory
요구사항에 따라 리팩토링을 진행하면서 `LottoTickets`를 생성해내던 LottoTicketfactory의 역할에 대한 의문이 들었다. 
처음 리팩토링에서는 객체를 많이 변경하지 않기 위해 수동 로또 번호들을 받고 자동 로또 갯수를 받아서
`LottoTicketFactory`에서 자동 로또 숫자들을 만들고 `LottoTickets`를 생성하는 역할로 진행했는데,
로또 티켓들 객체를 생성하기 위해 또 다른 `LottoTicketFactory`를 생성하는 것이 좋지 못한 방안이라는 생각이 들었다.

때문에 LottoTickets 객체를 생성할 때 로또 번호들의 리스트들을 받아서 (`List&lt;List&lt;LottoNumber&gt;&gt; lottoNumbersGroup`) `LottoTickets` 안에서 로또 티켓들을 생성하는 방식으로 변경했다.
그리고 기존 `LottoTicketFactory`는 `AutoNumbersFactory`로 변경하여
자동 로또 숫자 리스트를 만들어내는 역할로 변경해보았다 ! 

#### LottoNumber
0223 수업 때 로또 넘버의 범위에 제한이 있으니, 이를 미리 캐싱해서 사용하는 방법을 생각해보라고 하셨다.
생각을 해보고 캐싱하는 방법을 찾아보니 `HashMap`을 이용해서 캐싱을 구현할 수 있음을 깨달았다.
이로 생성자를 `private`로 막아 불필요한 객체 생성을 막고, 
`static block`에 의해 미리 캐싱된 `LottoNumber`에서 키값으로 접근해 해당 로또넘버를 가져오는 형식으로 리팩토링을 진행했다.
* LottoNumber 캐시 적용 부분
```java
static {
    IntStream.range(MIN_LOTTO_NUMBER, MAX_LOTTO_NUMBER + 1)
            .forEach(i -&gt; CACHE_LOTTO_NUMBERS.put(i, new LottoNumber(i)));
}

public static LottoNumber valueOf(int index) {
    validateLottoNumber(index);
    return CACHE_LOTTO_NUMBERS.get(index);
}</code></pre><h2 id="2단계-피드백">2단계 피드백</h2>
<h3 id="정적-팩터리-메소드">정적 팩터리 메소드</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/6f036cee-daa9-49b9-95c1-5b1925020fd1/image.png" alt="">
정적 팩터리 메서드에 대해 정리는 했었으나,
사실 언제 써야하고 언제 쓰지 말아야할지 아직 감이 안왔다 해야하나 🥲</p>
<p>그런데 크루들이랑 얘기를 해보니, 
정답은 없으나 자신이 쓰는 명분을 가지는게 좋을 것 같다는 결론을 내렸다.
사실 이때까지 정적 팩터리 메서드의 사용성을 제대로 인지하지 못하고 있었던 것 같다.
static이라는 명분 때문에 객체를 공유한다고 생각했으나,
정적 팩터리 메서드 내에서 새로운 객체를 생성해 반환한다면
상태를 공유하지 않는 것이다.</p>
<p>왜 static이라는 명목 때문에 정적 팩터리 메서드가 무조건
공유되는 객체를 만든다고만 생각했을까 🥲</p>
<p>때문에 이번 리팩토링에서는 정적 팩터리 메서드를 적극 사용해 보았다. </p>
<h3 id="많은-책임을-지고-있던-lottocontroller">많은 책임을 지고 있던 LottoController</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/12a6e507-efd1-4f00-9ba6-fd9c57bb9ab3/image.png" alt="">
이 당시 내가 구현한 LottoController는 </p>
<pre><code class="language-java">private LottoTickets buyLottoTickets(LottoCount lottoCount) {
    List&lt;List&lt;LottoNumber&gt;&gt; lottoNumbersGroup = new ArrayList&lt;&gt;();
    lottoNumbersGroup.addAll(createAllManualLottoTicket(lottoCount.getManualLottoCount()));
    lottoNumbersGroup.addAll(createAutoNumbers(lottoCount.getAutoLottoCount()));
    return new LottoTickets(lottoNumbersGroup);
}</code></pre>
<p>이런식으로 LottoTicket에 해당하는 <code>List&lt;LottoNumber&gt;</code>도 Controller에서 만들고,
이를 가지고 LottoTickets까지 만들어 낸다.
또 보다싶이 <code>List&lt;List&lt;LottoNumber&gt;&gt;</code>를 만들어 내기 위해 복잡한 코드를 가지고 있었다.</p>
<pre><code class="language-java">private List&lt;List&lt;LottoNumber&gt;&gt; createAllManualLottoTicket(int manualLottoCount) {
    OutputView.printInputManualLottoNumbers();
    return IntStream.range(0, manualLottoCount)
            .mapToObj(i -&gt; InputView.inputNumbers()
                    .stream()
                    .map(input -&gt; LottoNumber.valueOf(ParseUtil.parseInt(input)))
                    .collect(Collectors.toList()))
            .collect(Collectors.toList());
}</code></pre>
<p>이에 대해 남겨주신 피드백은 다음과 같다.
<img src="https://images.velog.io/images/new_wisdom/post/001e2dd8-9190-4b5f-a7de-2517dd7e6387/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/new_wisdom/post/3d3587e8-af0a-43a5-a164-a3fc966295f0/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/new_wisdom/post/9413baaf-ec08-45c4-a999-d47ef4092193/image.png" alt=""></p>
<p>이로 인해 전반적으로 많은 수정이 일어났다.
LottoTicket에 <code>auto()</code>, <code>manual()</code> 정적 팩터리 메서드를 만들고,
LottoTickets에도 <code>auto()</code> 정적 팩터리 메서드를 만들어 
LottoController에서 생성하고 있던 책임을 분배했다.</p>
<h4 id="lottoticket---auto-manual">LottoTicket - auto(), manual()</h4>
<pre><code class="language-java">public static LottoTicket auto() {
    return new LottoTicket(LottoNumbersFactory.generateAutoLottoNumbers());
}

public static LottoTicket manual(List&lt;String&gt; lottoNumberStrings) {
    return lottoNumberStrings.stream()
            .map(i -&gt; LottoNumber.valueOf(ParseUtil.parseInt(i)))
            .collect(collectingAndThen(toList(), LottoTicket::new));
}</code></pre>
<p>LottoTicket에서 <code>List&lt;String&gt;</code>을 받아 수동 로또 티켓을 생성하도록 리팩토링 해보았다 !</p>
<h4 id="lottotickets---auto">LottoTickets - auto()</h4>
<pre><code class="language-java">public static LottoTickets auto(int count) {
    return Stream.generate(LottoTicket::auto)
            .limit(count)
            .collect(collectingAndThen(toList(), LottoTickets::new));
}</code></pre>
<p>덕분에 LottoContoller에 있던 많은 책임이 분배되었다고 생각하고(?),
각 메서드 코드도 간결해졌다고 느낀다.</p>
<h4 id="lottocontroller-일부">LottoController 일부</h4>
<pre><code class="language-java">private LottoTickets buyLottoTickets(LottoCount lottoCount) {
    LottoTickets lottoTickets = createManualLottoTickets(lottoCount.getManualCount());
    lottoTickets.combine(LottoTickets.auto(lottoCount.getAutoCount()));
    return lottoTickets;
}

private LottoTickets createManualLottoTickets(int manualCount) {
    OutputView.printInputManualLottoNumbers();
    return Stream.generate(() -&gt; LottoTicket.manual(InputView.inputNumbers()))
                .limit(manualCount)
                .collect(collectingAndThen(toList(), LottoTickets::new));
}</code></pre>
<h3 id="lottotickets">LottoTickets</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/3f3db20b-c6f6-4134-b43c-35174ea78954/image.png" alt=""></p>
<p>피드백을 듣고 생각해보니 LottoTickets를 나는 단순히 LottoTicket의 모음이라고만 생각했었다.
(약간 Repository로 생각했던 것 같다.)</p>
<h4 id="리펙토링-전-lottotickets">리펙토링 전 LottoTickets</h4>
<pre><code class="language-java">private final List&lt;LottoTicket&gt; lottoTickets;

public LottoTickets(List&lt;List&lt;LottoNumber&gt;&gt; lottoNumbersGroup) {
    this.lottoTickets = new ArrayList&lt;&gt;(createLottoTickets(lottoNumbersGroup));
}

public List&lt;LottoTicket&gt; lottoTickets() {
    return Collections.unmodifiableList(lottoTickets);
}

private List&lt;LottoTicket&gt; createLottoTickets(List&lt;List&lt;LottoNumber&gt;&gt; lottoNumbersGroup) {
    return lottoNumbersGroup.stream()
            .map(LottoTicket::new)
            .collect(Collectors.toList());
}</code></pre>
<p>고민해보니 이전에 아래와 같이 WinningTicket에서 당첨 결과를 산출했었는데,</p>
<h4 id="리펙토링-전-winniglotto">리펙토링 전 WinnigLotto</h4>
<pre><code class="language-java">public LottoResult checkPrizes(LottoTickets lottoTickets) {
    return lottoTickets.lottoTickets().stream()
            .map(this::matchPrize)
            .collect(collectingAndThen(toList(), LottoResult::new));
}

public Prize matchPrize(LottoTicket lottoTicket) {
    int matchCount = getMatchingCount(lottoTicket);
    boolean isBonusNumber = isContainBonusNumber(lottoTicket);
    return Prize.findPrize(matchCount, isBonusNumber);
}

private int getMatchingCount(LottoTicket lottoTicket) {
    return (int) lottoTicket.lottoTicket().stream()
                .filter(winningTicket.lottoTicket()::contains)
                .count();
}

    private boolean isContainBonusNumber(LottoTicket lottoTicket) {
    return lottoTicket.lottoTicket()
                .stream()
                .anyMatch(lottoNumber -&gt; lottoNumber.equals(bonusNumber));
}</code></pre>
<p>이렇게 모든 메서드에서 LottoTicket의 값을 꺼내오고 있었다.
때문에 LottoTickets에 WinnigLotto를 주어 각 LottoTicket에게 비교하라는 메시지를 주는것이 더 옳다고 생각해서
LottoTickets에서 결과를 비교하는 역할을 부여하게 되었다.</p>
<p>또 Controller에서 로또 티켓을 생성하는 역할을 덜기 위해 메서드들이 바로 LottoTickets를 반환하도록 하면서
<code>ManualLottoTickets</code>와 <code>LottoTickets.auto</code>를생성하는데
생성된 이 두 <code>LottoTickets</code>들을 합치는 역할도 필요하다고 생각해서 
<code>combine()</code>할 수 있는 기능을 추가했다.</p>
<p>그런데 WinnigLotto에 있던 것들을 LottoTickets로 분배하니 WinningLotto의
역할이 다 빼앗겨 버린건 아닐까 고민이 되었지만,
<img src="https://images.velog.io/images/new_wisdom/post/044fae6a-acce-474a-8d3d-5b031dfe7196/image.png" alt=""></p>
<p>리뷰어 분께서 괜찮다고 말씀해주셨다.</p>
<p>미션을 진행하면 할수록 아직 배울 것이 많고 나의 부족함을 느낀다.
배울 것이 많다는 것은 느낄 성취감이 많다는 것이니 앞으로 화이팅하자 🏃‍♂️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] BigDecimal에 관한 고찰 🕵️‍♀️]]></title>
            <link>https://velog.io/@new_wisdom/Java-BigDecimal%EA%B3%BC-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-%EC%95%84%EB%A7%88%EC%B0%8C%EC%9D%98-%EB%84%88%EB%93%9C%EC%A7%93</link>
            <guid>https://velog.io/@new_wisdom/Java-BigDecimal%EA%B3%BC-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-%EC%95%84%EB%A7%88%EC%B0%8C%EC%9D%98-%EB%84%88%EB%93%9C%EC%A7%93</guid>
            <pubDate>Mon, 01 Mar 2021 04:42:58 GMT</pubDate>
            <description><![CDATA[<p>이번 미션에서 <code>BigDecimal</code>에 대한 언급이 많았는데,
<strong>도대체 그게 뭐지 🤷‍♀️ 나만 몰라 ❓</strong>
에서부터 출발한 BigDecimal에 대한 고찰 ~</p>
<p><del>이번주 회고에서 앞으로 포스팅을 내가 이해한 글을 설명하듯이 ! 작성하기로 다짐한
내용을 최대한 반영하려고 노력중 ✍️
누군가 이 글을 읽고 있다면 아 얘가 이런짓을 하고 있구나 가볍게 봐주길 ㅎㅎ 🙈</del></p>
<h2 id="bigdecimal을-왜-쓰지-">BigDecimal을 왜 쓰지 ?</h2>
<h4 id="test">Test</h4>
<p><img src="https://images.velog.io/images/new_wisdom/post/005a8086-2456-4ebb-9162-45a415ddb471/image.png" alt=""></p>
<p>과연 위 테스트 케이스는 통과를 할까? 정답은 👀</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/1a1ea170-2681-4f65-b8af-842b4316a1ae/image.png" alt=""></p>
<p>허허 어이없게도 실패합니다.
왜 실패하냐구요 ?
자바는 IEEE 754 부동 소수점 방식을 사용해서, 
정확한 실수를 저장하지 않고 최대한 완벽에 가깝기를 바라는 근사치 값을 저장하기 때문이다 !</p>
<p>지금은 단순히 개발자 하나가 테스트를 위해 작성한 코드이지만,
금융권에서 달러를 다루는 개발자가 double을 이용해서 이런 사소한 값 차이가 발생한다면 🙃</p>
<p>그렇다면 이 문제를 어떻게 해결하느냐 !
우리에겐 부동 소숫점 방식이 아닌, 정수를 이용해 실수를 표현하는 <code>java.math.BigDecimal</code> 클래스가 있다.</p>
<p>Java 언어에서 돈과 소수점을 다룬다면 BigDecimal은 <strong>선택이 아니라 필수</strong>다.</p>
<p>그렇다면 본격적으로 BigDecimal을 해부해 봅시다.</p>
<h2 id="bigdecimal-클래스">BigDecimal 클래스</h2>
<p><img src="https://images.velog.io/images/new_wisdom/post/239a603a-92ad-42c8-8db1-b9666e30b392/image.png" alt=""></p>
<p><code>BigDecimal</code> 클래스의 일부를 가져왔다.
여기서 간단하게 몇 가지 변수들의 쓰임 짚고 넘어가겠다.
<em>참고로 BigDecimal은 불변 클래스임</em></p>
<h4 id="변수">변수</h4>
<ul>
<li>intValue : 정수. 정수를 저장하는데 <code>BigInteger</code>를 사용한다.</li>
<li>scale : 지수. 정확히는 소수점 첫째 자리부터 0이 아닌 수로 끝나는 위치까지의 총 소수점 자리수이다. </li>
<li>precision : 정밀도. 정확히는 0이 아닌 수가 시작하는 위치부터 오른쪽부터 0이 아닌 수로 끝나는 위치까지의 총 자리수이다.
아래 출력 결과로 각 변수의 의미를 파악하자.
<img src="https://images.velog.io/images/new_wisdom/post/852fce1a-773b-423e-8925-a677f8bb63da/image.png" alt=""></li>
</ul>
<h2 id="bigdecimal의-생성">BigDecimal의 생성</h2>
<p>BigDecimal의 생성 방법은 여러가지가 있는데, 
문자열로 숫자를 표현하는 것이 일반적이다.
기본형 리터럴로는 표현할 수 있는 값의 한계가 있는데, 예를 들어
double 타입의 값을 그대로 전달할 경우
앞서 사칙연산 결과에서 본 것과 같이 예상과 다른 값을 얻을 수도 있다. </p>
<pre><code class="language-java">BigDecimal val;
val = new BigDecimal(&quot;12345.6789&quot;);
val = new BigDecimal(12345.678); // 오차가 날 수 있음
val = new BigDecimal(12345);
val = BigDecimal.valueOf(12345.67); // 오차가 날 수 있음
val = BigDecimal.valueOf(123456);</code></pre>
<p><img src="https://images.velog.io/images/new_wisdom/post/b2c32896-9f79-4931-871e-b38f26c09480/image.png" alt=""></p>
<p>실제로 인텔리제이도 String으로 바꾸라고 알려준다 👀 똑똑이</p>
<h2 id="bigdecimal의-비교">BigDecimal의 비교</h2>
<p>BigDecimal은 <code>Comparable&lt;BigDecimal&gt;</code>를 구현하고 있기 때문에,
<code>equals()</code>를 통해 내용을 비교할 수 있다.
여기서 주의할 점은 <code>12.01</code>과 <code>12.010</code>은 같지 않다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/0eec192e-2454-4905-be4b-48aa984f4f6e/image.png" alt=""></p>
<h2 id="bigdecimal의-타입-변환">BigDecimal의 타입 변환</h2>
<h3 id="문자열로-변환">문자열로 변환</h3>
<pre><code class="language-java">String toPlainString(); // 무조건 다른 기호 없이 숫자로만 표현
String toString(); // 필요시 지수 형태로 표현할 수도 있음</code></pre>
<p><img src="https://images.velog.io/images/new_wisdom/post/2be425da-32bf-497a-9f2e-47d2a96106a6/image.png" alt=""></p>
<p>또 <code>Number</code>를 상속받고 있기 때문에 <code>Number</code>의 기본형으로 변환하는 메서드를 가지고 있다.</p>
<pre><code class="language-java">int intValue()
long longValue()
float floatValue()
double doubleValue()</code></pre>
<p>또 BigDecimal을 정수형으로 변환하는 메서드 중,
이름 끝에 <code>Exact</code>가 붙은 것은 변환 결과가 변환 타입 범위에 속하지 않으면 
<code>ArithmeticException</code>을 발생시킨다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/6e38065d-30b2-4c9d-91b4-9d539b5130a3/image.png" alt=""></p>
<p>테스트 성공 !</p>
<h2 id="bigdecimal의-연산">BigDecimal의 연산</h2>
<p>먼저 기본적인 연산을 수행하는 메서드들이다.</p>
<pre><code class="language-java">BigDecimal add(BigDecimal val)
BigDecimal subtract(BigDecimal val)
BigDecimal multiply(BigDecimal val)
BigDecimal divide(BigDecimal val)
BigDecimal remainder(BigDecimal val)</code></pre>
<p><img src="https://images.velog.io/images/new_wisdom/post/b028fbb0-5e1d-4802-9cb6-ad0de651b9a1/image.png" alt=""></p>
<p>테스트 성공 !</p>
<p><strong>참고로 BigDecimal은 불변 객체이기 때문에 
연산 후 반환 타입이 BigDecimal인 경우 새로운 인스턴스가 반환된다.</strong></p>
<p>추가로 다른 연산과 달리 <code>divide()</code>은 메서드가 다양한 버전으로 오버로딩 되어있다.
어떻게 반올림할지(roundingMode), 몇 번째 자리(scale)에서 반올림 할건지를 지정할 수 있다.</p>
<h4 id="roundingmode">roundingMode</h4>
<p>반올림 처리 방법에 대한 것으로 BigDecimal에 정의된 다음 상수들에서 하나를 선택해 사용하면 된다.</p>
<ul>
<li>CEILING – 올림</li>
<li>FLOOR – 내림</li>
<li>UP – 양수일 경우 올림, 음수일 경우 내림</li>
<li>DOWN – 양수일 경우 내림, 음수일 경우 올림</li>
<li>HALF_UP – 반올림(5이상 올림, 5미만 버림)</li>
<li>HALF_EVEN – 반올림(반올림 자리의 값이 짝수면 HALF_DOWN, 홀수면 HALF_UP)</li>
<li>HALF_DOWN – 반올림(6이상 올림, 6미만 버림)</li>
<li>UNNECESSARY – 나눗셈 결과가 딱 떨어지지 않으면,<code>ArithmeticException</code> 발생</li>
</ul>
<h4 id="scale-변경">scale 변경</h4>
<p>소수점 위치를 바꾸고 싶을 때는 BigDecimal을 10으로 곱하거나 나누는 것이 아니라,
<code>setScale()</code>을 통해 scale 값을 변경한다.</p>
<pre><code class="language-java">BigDecimal setScale(int newScale)
BigDecimal setScale(int newScale, int roundingMode)
BigDecimal setScale(int newScale, RounfingMode mode)</code></pre>
<p>주의할 점은 <code>setScale()</code>로 scale을 줄이는 것은 10의 n제곱으로 나누는 것과 같으므로
오차가 발생할 수 있으니 roundingMode를 지정하는 것이 좋다.</p>
<h2 id="생성자-대신-valueof를-사용해라-">생성자 대신 valueOf()를 사용해라 !</h2>
<p>이 부분은 개인적인 고찰이니 혹시나 이 글을 누군가 읽고 잘못된 부분이 있다면 반박 부탁드림다 🙈
BigDecimal은 생성자와 정적 팩터리 메서드인 <code>valueOf()</code>를 사용해서 객체를 생성할 수 있는데,
<strong>과연 두 개는 어떤 것이 다를까 ❓</strong></p>
<p>고것이 궁금해졌다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/12cdd08d-4e5e-4353-b820-8ff52f4a185c/image.png" alt=""></p>
<p>일단 BigDecimal은 Integer클래스처럼 일부 값을 캐싱해 놓고 있다.
왜일까 스스로 답을 해보았는데,</p>
<p>BigDecimal의 주생성자를 가보면, 
<img src="https://images.velog.io/images/new_wisdom/post/6db0f234-25ad-4a33-9677-c7c7ecb84cac/image.png" alt=""></p>
<p>정말 장황한 생성자를 볼 수 있다.
때문에 BigDecimal이 성능이 느리다고도 하는데,
내 생각에는 이러한 이유 때문에도 캐싱을 해논게 아닌가 싶다.</p>
<p>이쯤에서 정적 팩터리 메서드인<code>valueOf()</code>로 가보면, </p>
<p><img src="https://images.velog.io/images/new_wisdom/post/df153dae-d768-461d-956c-996b2d689bf8/image.png" alt="">
정적 팩터리 메서드는 static 변수인 캐싱 값에 바로 접근할 수 있다.
때문에 이미 캐싱되어 있는 값이 존재한다면 생성자를 통하지 않고 그 값을 바로 반환한다.</p>
<p>➕ 
또 추가로
double실수값을 생성자로 생성해도 연산결과가 정확하지 않을 수 있으니, 
<code>valueOf()</code>를 사용해서 생성하는 것이 좋다고도 한다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/8ec4f2b7-16ac-40a1-bacd-c8e21bb76b82/image.png" alt=""></p>
<p>오호라 👀
요즘 정적 팩터리 메서드와 캐싱개념들에 대해 살펴봤는데,
BigDecimal을 뜯어보니 굉장히 흥미롭다 👻</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Weekly 회고] 4주차 회고]]></title>
            <link>https://velog.io/@new_wisdom/4%EC%A3%BC-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@new_wisdom/4%EC%A3%BC-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 28 Feb 2021 13:59:00 GMT</pubDate>
            <description><![CDATA[<p>약간 의식의 흐름대로😛 작성하는 이번주 회고 🌼</p>
<h3 id="리팩토링">리팩토링</h3>
<p>1차 미션이 머지되고 2차 미션을 위한 리팩토링을 거치는 중이었는데,
화요일 강의에서 Exception에 대해 배우면서,
LottoNumber에 대한 캐시 적용을 도전해보라고 하셨다.</p>
<p>사실 캐시를 어떻게 적용해야할지 막막해서 레퍼런스를 엄청 찾아다니다가,
HashMap으로 캐시 개념을 적용할 수 있음을 발견하고 🕵️‍♀️ 
이를 적용하기 위한 리팩토링이 시작되었다.</p>
<p>또 &quot;수동 로또&quot; 기능이 추가되면서 한 기능을 추가하기 위해 우수수 수정되야 하는
내 코드의 문제점도 많이 발견하게 되었다 👩‍🦳</p>
<p>추가적인 요구사항이 있을 때 객체들이 적절한 역할을 나눠가졌다면
큰 변경사항이 없었겠지만, 내 코드는 적절한 역할 분담이 되지 못해서인지
많은 수정이 일어났다.</p>
<p>이때 아쉬웠던 점은 캐시 개념을 적용하고, 예외 처리 방법을 바꾸고, 
전반적인 객체의 책임을 리팩토링 하면서 TDD를 염두하지 못했다는 점이다.
전반적으로 수정되야할 부분이 너무 많다보니, 정말 정신없는 리팩토링 기간이었다 🙃</p>
<p>때문에 이에 대한 문제를 느끼고 있었는데, 마침 또 금요일 강의에서 
이 문제에 대해서 다뤄주셨다.
<strong>&quot;점진적 리팩토링&quot;</strong>
변경해서 컴파일 에러가 날 것 같은 테스트 메서드를 일단 복제해놓고,
테스트 메서드를 하나씩 변경해가며 안전하게 TDD로 리팩토링을 진행하는 것이다.
이 강의를 좀 더 일찍 들었다면 🥲</p>
<h3 id="블로그-글에-대하여">블로그 글에 대하여</h3>
<p>우테코를 진행하면서 몇몇 크루들의 블로그 글이나, 자신이 배운 내용을 정리한 글들을 보게 된다.</p>
<p>그러면서 내 블로그 글도 돌아보며, 많이 반성하게 되었던 것 같다.</p>
<p>나는 어떠한 개념을 책이나 레퍼런스를 보면서 공부할 때, 단순히 눈으로 읽으면
머릿 속에 남지 않기 때문에 무조건 블로그에 기록하면서 공부하는 습관이 있다.</p>
<p>이 방식 자체는 나에게 굉장히 유익하다. 
눈으로 휘리릭 읽고 끝내면 머릿 속에 남지 않지만,
확실히 적으면서 공부하는 방법이 머릿 속에 저장하는데 더 큰 효율을 내는 것 같다.</p>
<p>허나, 요즘 내 블로그 글들을 보면, 그냥 단순히 &quot;기록&quot;하기에 바빴던 것 같다.
내가 배운 개념을 내가 이해한 대로 &quot;정리&quot;하는 것이 아닌,
&quot;나 오늘 이거 공부했다!&quot; 이렇게 기록하기에 급급했던 것 같다.</p>
<p>공부하면서 실시간으로 기록하고, 이를 그냥 띡하니 블로그에 올려버리니
단순히 기록이 될 뿐, 내 머릿 속에 정리되기에는 부족한 방법이었던 것 같다.</p>
<p>또 이렇게 작성한 글은 스스로 다시 돌아보지도 않았었는데,
그렇다면 이게 정말 머릿 속에 기록하는 것이 맞나라는 생각이 들었다.</p>
<p><del>그러다가 블로그 퀄리티?를 올리기 위해 블로그를 깃블로그로 옮길까 진지하게 고민하다가,
나의 입장에서는 깃블로그는 세팅하는데 시간이 무수하게 걸릴 것 같다.
지금은 학습에 좀 더 시간을 투자하는게 옳은 것 같고, 
블로그 유형에 연연하지 말고 나의 콘텐츠에 집중하는 것이 옳다는 생각이 들어서 깔끔히 포기했다.</del></p>
<p>앞으로 내가 블로그 글을 <strong>누군가에게 설명하듯이, 또는 내가 이해한 대로</strong> 작성해 나갈 것이다.</p>
<p>이렇게 결심하게 된 이유가 또 있는데 이는 바로 아래에 기록한다.</p>
<h3 id="학습-로그">학습 로그</h3>
<p>이번 미션부터 학습로그를 함께 작성해 리뷰 요청을 보내고 있다.
이번주 금요일, 우리 데일리에서는 각자 이번 미션동안 작성한 학습 로그를 기반으로
페어를 맺어 2-3분간 자신이 배운 내용을 서로에게 발표하는 시간을 가졌다.</p>
<p>분명 글로 기록하면서 내 머릿 속에 기록했다고 생각했는데,
막상 누군가에게 설명하려니 쉽지 않았다.
내가 이해한 것을 말하려고 하니, 내가 스스로 설명할 수 없는 부족한 개념들이 보였다.</p>
<p>한 개념을 완벽히 이해했다는 것은 누군가에게 그 개념을 설명할 줄 알아야 한다.
지금까지 내 학습 방법은 그렇지 못했던 것 같다.
단지 기록하기에 급급했던 것 같다.
<strong>내가 배운 개념들을 말로 설명할 수 있도록, 내 것으로 만드는 연습을 해야겠다.</strong></p>
<p>또 이번 한 주 학습 로그를 돌아보며 느낀 것은 
나는 무언가 배우는데 욕심이 많은데 그래서 그런지 한 번에 여러 개념을 
빨리 배우고 싶어서 하나를 깊게 하기 보다는 여러 방면을 빨리 빨리 손대려고 했던 것 같다.
이렇게 공부하는 내용도 블로그에 기록하려다 보니 글에 성의가 없어진 것 같다고도 느낀다.
학습 로그를 보면 많은 것들을 이번 미션동안 배웠다고 생각되는데,
&quot;여기서 아무거나 골라서 설명해봐!&quot; 라고 하면 어버버하게 될 것 같다.</p>
<p><strong>많은 것을 배우려 하기 보다는, 
계속해서 물음표를 던지고 깊게 꾸준히 배우려는 자세를 취해야겠다.</strong></p>
<h3 id="학습">학습</h3>
<p>쨌든 회고를 하다보니 나의 학습 방법의 문제들을 느꼈으나,
나름대로 이번 한주도 열심히 학습해왔다.
이는 학습로그를 참조하면 될 것 같다.
정말 아쉬운 점은 토요일에 제네릭에 대해 공부하고,
이때는 정말 내가 이해한 개념을 정리하듯이 글을 써나가고 있었는데
글이 저장이 안되서 날라간 것이다 👩‍🦳
진좌 억울홰 . . . </p>
<h3 id="즐거운-데일리-조">즐거운 데일리 조</h3>
<p>우테코 생활을 하면서 즐거운 정말 큰 이유 중 하나는 바로 우리 데일리 조 덕분이 아닐까 생각한다.
이번주 수요일은 랜선 회식을 진행했다.
나는 브라운이 준 3만원 상품권 찬스로 무려 대방어를 시켜먹었다.
각자 배달음식을 먹으면서 수다를 떨다가 멤버들에 더 알기 위해 
멤수타도 진행했다. 랜선이지만 정말 즐거운 회식이었다. 👻</p>
<p>또 우리 데일리 조는 gather에서 진행하는데, 데일리 미팅 뿐만 아니라 그냥 
gather에 상주해 있기도 한다.
데일리 미팅은 매일 크루들이 데일리 마스터가 되어서 게더를 이용해 진행하는데,
매일 다들 기발하고 즐거운 주제를 가져와서 활기차게 시작할 수 있는 것 같다.
덕분에 크루들과 친밀해지고 정말 즐거운 시간이다.</p>
<p>또 이번주는 크루들이 리뷰를 기다리는 시간이 있어서 그런지 게더에서 재밌는 일들이 많이 진행됐다.
<del>테트리스도 하고, 한 크루의 라방도 구경하고 . . . ㅋㅋ</del>
게더에서 서로 작업하다가 이런 저런 농담을 던지는데 진짜 웃다가 쓰러진다.
유쾌한 사람들과 함께 할 수 있어서 정말 즐겁다.</p>
<p>오프라인으로 한번도 본 적 없는 사람들이지만, 벌써부터 친밀해진 것 같아서 좋다.</p>
<h3 id="시간-관리">시간 관리</h3>
<p>계속해서 아침 일찍 일어나기를 실천(?)하고 있다.
저번주는 사실 조금 무리했어서 과장 한그릇 보태면 주말을 시체처럼 보냈는데,
이번주는 스스로 적정한 수면 시간을 보장(?)했더니 
매일 일정한 시간에 일어날 수 있었던 것 같았다.
덕분에 한 주를 지나도 피곤함을 느끼지 않은 것 같다.
체력 관리 성공 🔥</p>
<p>아무리 생각해도 효율적인 공부 시간과 내 시간을 보장할 수 있는 아침 일찍 일어나기는 탁월한 선택인 것 같다 ✔️</p>
<p>이번 한 주 시간관리를 어떻게 했는지 돌아보면,
사실 개인적으로 처리해야하는 잡일(?)이 많이 생겨서 
붕 뜨는 시간이 많았던 것 같다.
이번주는 내가 하루에 무엇을 했는지 자세히 적지 못했다.
분명 저번주에 내가 매일마다 무엇을 했는지 기록하기로 다짐했으나
변명을 대보자면 잡일(?) 때문에 하루 마무리가 애매하게 흘러가버렸다 🌚
다음주는 정말로 <strong>매일마다 간단하게 내가 한 일을 정리하는 시간을 가져야겠다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Stream 부수기]]></title>
            <link>https://velog.io/@new_wisdom/Java-Stream-1</link>
            <guid>https://velog.io/@new_wisdom/Java-Stream-1</guid>
            <pubDate>Thu, 25 Feb 2021 00:37:56 GMT</pubDate>
            <description><![CDATA[<p>코드를 짜다보면 가독성과 간결함을 위해 stream을 자주 쓰게 된다.
프리코스 때 Stream에 대해 정리했었으나,
내가 쓴 글을 리팩토링(ㅎ) 해보면서 다시 개념을 익혀야 겠다.</p>
<h2 id="스트림">스트림?</h2>
<p>배열 또는 컬렉션 인스턴스에 저장된 데이터를 꺼내서 파이프에 흘려보낸다.</p>
<ul>
<li>중간 연산 : 마지막이 아닌 위치에서 진행이 되어야 하는 연산</li>
<li>최종 연산 : 마지막에 진행이 되어야 하는 연산
스트림은 중간 연산과 최종 연산을 진행하기 좋은 구조로 배치된 복사본이라 할 수 있다.</li>
</ul>
<h3 id="스트림의-특성">스트림의 특성</h3>
<h4 id="가독성과-간결함">가독성과 간결함</h4>
<p>컬렉션이나 배열에 데이터를 담고 원하는 결과를 얻기 위해 
for문과 Iterator를 이용해 작성한 코드는 가독성이 떨어지고 재사용성도 떨어진다.</p>
<h4 id="데이터-소스-추상화">데이터 소스 추상화</h4>
<p>어떤 메소드로 처리하기 위해 데이터 소스마다 다른 방식으로 다뤄야 하는 문제를
스트림을 통해 데이터 소스가 무엇이던 간에 같은 방식으로 다룰 수 있게 되었다.
이는 코드의 재사용성을 가져온다.</p>
<pre><code class="language-java">Stream&lt;String&gt; listStream = strList.stream();
Stream&lt;String&gt; arrayStream = Arrays.stream(strArr);

listStream.sorted().forEach(System.out::println);
arrayStream.sorted().forEach(System.out::println);</code></pre>
<p>두 스트림의 데이터 소스는 서로 다르지만, 정렬하고 출력하는 방법은 같다.</p>
<h4 id="데이터-소스를-변경하지-않는다">데이터 소스를 변경하지 않는다.</h4>
<p>스트림은 데이터 소스로 부터 데이터를 읽기만 할 뿐, 
데이터 소스를 변경하지 않는다.
필요시에만 정렬된 결과를 컬렉션이나 배열에 담아서 반환할 수도 있다.</p>
<pre><code class="language-java">List&lt;String&gt; sortedList = listStream.sorted().collect(Collections.toList());</code></pre>
<h4 id="스트림은-일회용이다">스트림은 일회용이다.</h4>
<p>Iterator처럼 일회용이다. 한번 사용하면 닫혀서 다시 사용할 수 없다.
필요하다면 스트림을 다시 생성해야한다.</p>
<pre><code class="language-java">listStream.sorted().forEach(System.out::print);
int numOfElement = listStream.count(); //에러- 스트림이 이미 닫혔다.</code></pre>
<h4 id="내부-반복">내부 반복</h4>
<p>스트림이 간결한 이유중 하나가 반복문을 메서드 내부에 숨기는 &#39;내부 반복&#39; 덕분이다.
<code>forEach()</code>는 스트림에 정의된 메서드 중의 하나로 매개변수에 대입된 
람다식을 데이터 소스의 모든 요소에 적용한다.</p>
<pre><code class="language-java">stream.forEach(System.out::println);</code></pre>
<h2 id="스트림-생성하기">스트림 생성하기</h2>
<h3 id="스트림의-생성">스트림의 생성</h3>
<h4 id="메소드">메소드</h4>
<p>스트림 생성과 관련해 <code>Stream&lt;T&gt;</code> 인터페이스에 정의되어 있는 static 메소드는 두 개가 있다.</p>
<pre><code>static &lt;T&gt; Stream&lt;T&gt;(T t)
static &lt;T&gt; Stream&lt;T&gt; of(T...values)</code></pre><p>이 메소드에 스트림 생성에 필요한 데이터를 인자로 직접 전달할 수 있다. </p>
<h4 id="example">Example</h4>
<pre><code>class StreamOfStream {
    public static void main(String[] args) {
        // ex 1
        Stream.of(11, 22, 33, 44)
            .forEach(n -&gt; System.out.print(n + &quot;\t&quot;));
        System.out.println();

        // ex 2
        Stream.of(&quot;So Simple&quot;)
            .forEach(s -&gt; System.out.print(s + &quot;\t&quot;));
        System.out.println();

        // ex 3 세 개의 문자열로 이뤄진 스트림이 생성되는 것이 아닌
        // sl이 참조하는 하나의 인스턴스만 존재한다.
        List&lt;String&gt; sl = Arrays.asList(&quot;Toy&quot;, &quot;Robot&quot;, &quot;Box&quot;);
        Stream.of(sl)
            .forEach(w -&gt; System.out.print(w + &quot;\t&quot;));
        System.out.println();       
    }
}</code></pre><p>of 메소드에 컬렉션 인스턴스를 전달하면 해당 인스턴스 하나로 이뤄진 스트림이 생성된다. 
하지만 배열을 전달하면 하나의 배열로 이뤄진 스트림이 생성되지 않고,
배열에 저장된 요소로 이뤄진 스트림이 생성된다.</p>
<h3 id="배열">배열</h3>
<p>배열에 저장된 데이터를 대상으로 스트림을 생성할 때 호출되는 대표 메소드는 다음과 같다.</p>
<pre><code class="language-java">public satic &lt;T&gt; Stream&lt;T&gt; stream(T[] array) // Arrays 클래스에 정의되어 있다</code></pre>
<pre><code class="language-java">class StringStream {
    public static void main(String[] args) {
        String[] names = {&quot;YOON&quot;, &quot;LEE&quot;, &quot;PARK&quot;};

        // 스트림 생성
        Stream&lt;String&gt; stm = Arrays.stream(names);

        // 최종 연산 진행
        stm.forEach(s -&gt; System.out.println(s));
    }
}</code></pre>
<p>forEach는 최종 연산이며 메소드의 매개변수형은 <code>Consumer&lt;T&gt;</code> 이므로 람다식을 인자로 전달해야하며, 
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 accept 메소드를 호출한다.</p>
<h3 id="컬렉션-인스턴스">컬렉션 인스턴스</h3>
<p>컬렉션 인스턴스를 대상으로 스트림을 생성할 때 호출되는 메소드는 다음과 같다.</p>
<pre><code class="language-java">default Stream&lt;E&gt; stream()</code></pre>
<pre><code>class ListStream {
    public static void main(String[] args) {

        List&lt;String&gt; list = Arrays.asList(&quot;Toy&quot;, &quot;Robot&quot;, &quot;Box&quot;);

        list.stream()
          .forEach(s -&gt; System.out.print(s + &quot;\t&quot;));

        System.out.println();
    }
}</code></pre><h3 id="특정-범위의-정수">특정 범위의 정수</h3>
<p><code>IntStream</code>과 <code>LongStream</code>은 지정된 범위의 연속된 정수를 스트림으로 생성해서
반환하는 <code>range()</code>와 <code>rangeClosed()</code>를 가지고 있다.</p>
<pre><code>IntStream intStream = IntStream.range(1, 5); // 1,2,3,4,
IntStream intStream = IntStream = Intstream.rangeClosed(1, 5); // 1,2,3,4,5 </code></pre><p><code>range</code>는 end가 범위에 포함되지 않고 <code>rangeClosed</code>는 포함된다.</p>
<h3 id="람다식---iterate-generate">람다식 - iterate(), generate()</h3>
<p>Stream 클래스의 <code>iterate()</code>와 <code>generate()</code>는 람다식을 매개변수로 받아서,
이 람다식에 의해 계산되는 값들을 요소로 하는 무한 스트림을 생성한다.</p>
<p>이때 생성되는 스트림은 무한하기 때문에 <code>limit()</code>를 호출하여 특정 사이즈로 제한해주는 것이 좋다.</p>
<h4 id="iterate">iterate()</h4>
<pre><code class="language-java">Stream&lt;Integer&gt; evenStream = Stream.iterate(0, n -&gt; n+2).limit(5);
// 0, 2, 4 ...</code></pre>
<p>씨드로 지정된 값부터 시작해서,  람다식에 의해 계산된 결과를 다시 시드 값으로 해서 
계산을 반복한다.</p>
<h4 id="generate">generate()</h4>
<pre><code class="language-java">Stream&lt;Integer&gt; randomStream = Stream.generate(Math::random).limit(5);</code></pre>
<p><code>iterate()</code>처럼 람다식에 의해 계산되는 값을 요소로 하는 무한 스트림을 생성해서
반환하지만, <code>iterate()</code>와 달리 이전 결과를 이용해서 다음 요소를 계산하지 않는다.</p>
<h3 id="빈-스트림">빈 스트림</h3>
<p>요소가 하나도 없는 비어있는 스트림을 생성할 수도 있다.
스트림에 연산을 수핸한 결과가 하나도 없을 때, null보다 빈 스트림을 반환하는게 낫다.</p>
<pre><code class="language-java">Stream emptyStream = Stream.empty(); // empty() 는 빈 스트림을 생성해서 반환한다.
long count = emptyStream.count(); // count값은 0</code></pre>
<p>여기서 <code>count()</code>는 요소의 갯수를 반환한다.</p>
<h2 id="스트림의-연산">스트림의 연산</h2>
<h4 id="지연-처리">지연 처리</h4>
<pre><code class="language-java">class MyFirstStream2 {
    public static void main(String[] args) {
        int[] ar = {1, 2, 3, 4, 5};

        int sum = Arrays.stream(ar) // 스트림을 생성
                        .filter(n -&gt; n%2 == 1) // filter 통과
                        .sum(); // sum을 통과시켜 그 결과를 반환

        System.out.println(sum);
    }
}</code></pre>
<p>위 예제에서 쓰인 두 메소드는 다음과 같다.</p>
<pre><code class="language-java">public static IntStream stream(int[] array)
IntStream filter(IntPredicate predicate)</code></pre>
<p>filter와 sum 메소드는 IntStream의 인스턴스 메소드이다.</p>
<p>스트림의 연산은 &quot;지연 처리&quot; 방식으로 동작한다.
최종 연산이 수행 되기 전까지는 중간 연산이 수행되지 않는다.</p>
<p>위 예제에서는 sum이 호출될 때까지 filter의 호출 결과는 스트림에 반영되지 않는다.
최종 연산인 sum이 호출되어야만 filter의 호출 결과가 스트림에 반영된다.
이처럼 최종 연산이 생략되면 중간 연산이 의미가 없다.</p>
<h3 id="스트림의-중간-연산">스트림의 중간 연산</h3>
<p>연산 결과가 스트림인 연산으로, 스트림에 연속해서 중간 연산할 수 있다.</p>
<h3 id="filter-필터링">filter (필터링)</h3>
<p>스트림을 구성하는 데이터 중 일부를 조건에 따라 걸러내는 행위를 의미한다.</p>
<h4 id="메소드-1">메소드</h4>
<pre><code class="language-java">Stream&lt;T&gt; filter(Predicate&lt;? super T&gt; predicate) // Stream&lt;T&gt;에 존재</code></pre>
<p>매개변수 형이 Predicate이므로 test 메소드의 구현에 해당하는 람다식을 
인자로 전달해야 한다.
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 test를 호출하고,
그 결과가 true이면 해당 데이터를 스트림에 남긴다.</p>
<pre><code class="language-java">class FilterStream {
    public static void main(String[] args) {
        int[] ar = {1, 2, 3, 4, 5};
        Arrays.stream(ar)
            .filter(n -&gt; n%2 == 1) // 홀수만 통과
            .forEach(n -&gt; System.out.print(n + &quot;\t&quot;));
        System.out.println();

        List&lt;String&gt; sl = Arrays.asList(&quot;Toy&quot;, &quot;Robot&quot;, &quot;Box&quot;);
        sl.stream()
            .filter(s -&gt; s.length() == 3) // 길이가 3이면 통과
            .forEach(s -&gt; System.out.print(s + &quot;\t&quot;));
        System.out.println();       
    }
}</code></pre>
<h3 id="map-맵핑">map (맵핑)</h3>
<p>스트림 요소에서 저장된 값 중에서 원하는 필드만 뽑아내거나 특정 형태로 변환해야 할 떄가 있다.
맵핑을 진행하면 스트림의 데이터 형이 달라지는 특징이 있다.</p>
<h4 id="메소드-2">메소드</h4>
<pre><code class="language-java">&lt;R&gt; Stream&lt;R&gt; map(Function&lt;? super T, ? extends R&gt; mapper)</code></pre>
<p>매개변수 형이 Function이므로 apply 메소드의 구현에 해당하는 람다식을 
인자로 전달해야 한다.
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 apply를 호출하고,
그 결과로 반환되는 값을 모아 새 스트림을 생성한다.</p>
<pre><code class="language-java">class MapToInt {
    public static void main(String[] args) {
        List&lt;String&gt; ls = Arrays.asList(&quot;Box&quot;, &quot;Robot&quot;, &quot;Simple&quot;);

        ls.stream()
          .map(s -&gt; s.length())
          .forEach(n -&gt; System.out.print(n + &quot;\t&quot;));

        System.out.println();
    }
}</code></pre>
<h4 id="map-vs-flatmap">map vs flatMap</h4>
<h5 id="map의-메소드">map의 메소드</h5>
<pre><code class="language-java">&lt;R&gt; Stream&lt;R&gt; map(Function&lt;T, R&gt; mapper)</code></pre>
<p>map에 전달할 람다식에서는 스트림을 구성할 데이터만 반환하면 된다.</p>
<h5 id="flatmap의-메소드">flatMap의 메소드</h5>
<pre><code class="language-java">&lt;R&gt; Stream&lt;R&gt; flatMap(Function&lt;T, Stream&lt;R&gt;&gt; mapper)</code></pre>
<p>flatMap에 전달할 람다식에서는 스트림을 생성하고 이를 반환해야 한다.</p>
<h3 id="filter--map">filter &amp; map</h3>
<h4 id="example-1">example</h4>
<pre><code class="language-java">int sum = ls.stream()
    .filter(p -&gt; p.getPrice() &lt; 500)
    .mapToInt(t -&gt; t.getPrice())
    .sum();</code></pre>
<h3 id="sorted">sorted</h3>
<h4 id="메소드-3">메소드</h4>
<pre><code class="language-java">Stream&lt;T&gt; sorted()
Stream&lt;T&gt; sorted(Comparator&lt;? super T&gt; compatator)</code></pre>
<p><code>sorted()</code>는 지정된 Comparator로 스트림을 정렬하는데, Comparator대신 
int 값을 반환하는 람다식을 사용할 수도 있다.
Comparator를 지정하지 않으면 스트림 요소의 기본 정렬 기준으로 정렬한다.
하지만 스트림 요소가 Comparable을 구현한 클래스가 아니면 예외가 발생한다.
정렬에 사용되는 메서드의 개수가 많지만 기본적인 메서드는 <code>comparing()</code>이다.</p>
<pre><code class="language-java">comparing(Function&lt;T, U&gt; keyExtractor)
comparing(Function&lt;T, U&gt; keyExtractor, Comparator&lt;U&gt; keyComparator)</code></pre>
<p>스트림 요소가 Comparable을 구현한 경우, 매개변수 하나짜리를 사용하면 되고,
그렇지 않으면 추가적인 매개변수로 정렬기준(Comparator)을 따로 지정해줘야 한다.</p>
<p>정렬 조건을 추가할 때는 <code>thenComparing()</code>을 사용한다.</p>
<h4 id="example-2">Example</h4>
<p>학생 스트림을 반별, 성적순, 이름 순으로 정렬하는 예시이다.</p>
<pre><code class="language-java">student.sorted(Comparator.comparing(Student::getBan)
    .thenComparing(Student::getTOtalScore)
        .thenComparing(Student::getName)
        .forEach(System.out.println);</code></pre>
<h3 id="peek">peek</h3>
<p>스트림을 이루는 모든 데이터 각각을 대상으로 특정 연산을 진행하는 행위를 &quot;루핑&quot;이라 한다.
forEach는 루핑으로 최종연산이지만, 중간연산에도 루핑 메소드가 있다.</p>
<h4 id="메소드-4">메소드</h4>
<pre><code>// Stream&lt;T&gt;의 메소드
Stream&lt;T&gt; peek(Consumer&lt;? super T&gt; action)</code></pre><h4 id="example-3">Example</h4>
<pre><code>class LazyOpStream {
    public static void main(String[] args) {
        // 최종 연산이 생략된 스트림의 파이프 라인
        // 아무 것도 출력되지 않는다.
        IntStream.of(1, 3, 5)
            .peek(d -&gt; System.out.print(d + &quot;\t&quot;));
        System.out.println();


        // 최종 연산이 존재하는 파이프 라인
        IntStream.of(5, 3, 1)
            .peek(d -&gt; System.out.print(d + &quot;\t&quot;))
            .sum();            
        System.out.println();
    }
}</code></pre><h2 id="스트림의-최종-연산">스트림의 최종 연산</h2>
<p>최종 연산은 스트림의 요소를 소모해서 결과를 만들어낸다.
그래서 최종 연산 후에는 스트임니 닫혀 더 이상 사용할 수 없다.
최종 연산의 결과는 스트림의 요소의 합과 같은 단일 값이거나, 
스트림의 요소가 담긴 배열 또는 컬렉션일 수 있다.</p>
<h3 id="foreach">forEach</h3>
<p>지정된 작업을 스트림의 모든 요소에 대해 수행한다.
주의할 점은 <code>forEach()</code>는 스트림의 요소를 소모하면서 작업을 수행하므로 같은 스트림에 <code>forEach()</code>를 두 번 호출할 수 없다.</p>
<h4 id="메소드-5">메소드</h4>
<pre><code>// Stream&lt;T&gt;의 메소드
void forEach(Consumer&lt;? super T&gt; action)</code></pre><p><code>peek()</code>과 달리 스트림의 요소를 소모하는 최종 연산이기 때문에 반환형이 void이다.</p>
<h3 id="reduce">reduce</h3>
<p>스트림 요소를 줄여나가면서 연산을 수행하고 최종 결과를 반환한다.
처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소와 연산한다.
이 과정에서 스트림의 요소를 하나씩 소모하게 되며, 스트림의 모든 요소를 소모하면 그 결과를 반환한다.</p>
<p>스트림의 요소가 하나도 없는 경우, 초기값이 반환되므로 반환타입이 <code>Optional&lt;T&gt;</code>가 아니라 <code>T</code>이다.</p>
<h4 id="메소드-6">메소드</h4>
<pre><code class="language-java">T reduce(T identity, BinaryOperator&lt;T&gt; accumulator) // Stream&lt;T&gt;에 존재</code></pre>
<p>reduce는 전달하는 람다식에 의해 연산의 내용이 결정된다.</p>
<p><strong><code>BinaryOperator&lt;T&gt;</code>의 추상 메소드</strong></p>
<pre><code>T apply(T t1, T t2)</code></pre><p>reduce 호출 시 메소드 apply에 대한 람다식을 인자로 전달해야 한다.</p>
<pre><code class="language-java">class ReduceStream {
    public static void main(String[] args) {
        List&lt;String&gt; ls = Arrays.asList(&quot;Box&quot;, &quot;Simple&quot;, &quot;Complex&quot;, &quot;Robot&quot;);

        BinaryOperator&lt;String&gt; lc = 
            (s1, s2) -&gt; { 
               if(s1.length() &gt; s2.length())
                   return s1;
               else 
                   return s2;                   
            };

        String str = ls.stream()
                      .reduce(&quot;&quot;, lc); // 스트림이 빈 경우 빈 문자열 반환

        System.out.println(str); // Complex
    }
}</code></pre>
<p>reduce 메소드는 스트림이 빈 경우에 첫 번째 인자로 전달된 값을 반환한다.</p>
<h3 id="allmatch-anymatch-nonematch">allMatch, anyMatch, noneMatch</h3>
<p>스트림의 요소에 대해 지정된 조건에 모든 요소가 일치하는 지, 일부가 일치하는지,
아니면 어떤 요소도 일치하지 않는지 확인하는데 사용할 수 있다.</p>
<h4 id="메소드-7">메소드</h4>
<pre><code>boolean allMatch(Predicate&lt;? super Y&gt; predicate)

boolean anyMatch(Predicate&lt;? super Y&gt; predicate)

boolean noneMatch(Predicate&lt;? super Y&gt; predicate)</code></pre><ul>
<li>allMatch : 스트림의 데이터가 조건을 모두 만족하는가?</li>
<li>anyMatch : 스트림의 데이터가 조건을 하나라도 만족하는가?</li>
<li>noneMatch : 스트림의 데이터가 조건을 하나도 만족하지 않는가?<h3 id="findany-findfirst">findAny, findFirst</h3>
<code>filter()</code>와 함께 쓰여서 조건에 맞는 스트림의 요소가 있는지 확인하는데 사용된다.
둘의 반환 타입은 <code>Optionsnal&lt;T&gt;</code>이며, 스트림의 요소가 없을 때 빈 Optional 객체를 반환한다.<h4 id="example-4">Example</h4>
<pre><code class="language-java">Optional&lt;Student&gt; result = student.filer(s -&gt; s.getTotalScore() &lt;= 100).findFirst();</code></pre>
<h3 id="collect">collect</h3>
파이프라인을 통해서 가공되고 걸러진 데이터를 최종 연산 과정에서 별도로 저장이 필요할 때 사용한다.<h4 id="메소드-8">메소드</h4>
<pre><code>// Stream&lt;T&gt;의 메소드
&lt;R&gt; R collect(Supplier&lt;R&gt; supplier, 
              BiConsumer&lt;R, ? super T&gt; accumulator,
              BiConsumer&lt;R, R&gt; combiner)</code></pre></li>
</ul>
<h4 id="example-5">Example</h4>
<pre><code>class CollectStringStream {
    public static void main(String[] args) {
        String[] words = {&quot;Hello&quot;, &quot;Box&quot;, &quot;Robot&quot;, &quot;Toy&quot;};
        Stream&lt;String&gt; ss = Arrays.stream(words);

        List&lt;String&gt; ls = ss.filter(s -&gt; s.length() &lt; 5)
                          .collect(
                              () -&gt; new ArrayList&lt;&gt;(),
                              (c, s) -&gt; c.add(s),
                              (lst1, lst2) -&gt; lst1.addAll(lst2));

        System.out.println(ls); // [Box, Toy]
    }
}</code></pre><p>첫 번째 매개변수인 람다식을 기반으로 데이터를 저장할 저장소를 생성한다.
두 번째 매개변수인 람다식에서의 첫 번째 매개변수(c)는 
collect의 첫번째 인자를 통해서 생성된 컬렉션 인스턴스이며,
두 번째 매개변수(s)는 스트림을 이루는 데이터 이다.
세 번째 매개변수인 람다식은 병렬 스트림이 아닌 순차 스트림일 경우 사용되지 않는다. </p>
<h2 id="collect-1">collect()</h2>
<p>스트림의 요소를 수집하는 최종 연산으로 <code>reduce()</code>와 유사하다.
collect()가 스트림의 요소를 수집하려면, 어떻게 수집할 것인가에 대한 방법이 정의되어
있어야 하는데, 이 방법을 정의한 것이 컬렉터이다.</p>
<h3 id="컬렉터">컬렉터</h3>
<p>컬렉터는 <code>Collector</code> 인터페이스를 구현한 것으로, 직접 구현할 수도 있고 미리 작성된 것을 사용할 수도 있다.
다양한 static 메서드를 가지고 있다.</p>
<ul>
<li>collect() : 스트림의 최종연산, 매개변수로 컬렉터를 필요로 한다.</li>
<li>Collector : 인터페이스. 컬렉터는 이 인터페이스를 구현해야한다.</li>
<li>Collectors : 클래스. static 메서드로 미리 작성된 컬렉터를 제공한다.</li>
</ul>
<p>Collector는 인터페이스이기 때문에 직접 구현해서 컬렉터를 만들어야 한다.</p>
<h3 id="collect-2">collect()</h3>
<p><code>collect()</code>는 매개변수 타입이 Collector인데, 매개변수가 Collector를 구현한 클래스의 객체여야 한다.
<code>collect()</code>는 이 객체에 구현된 방법대로 스트림의 요소를 수집한다.
<em>sort()할 때 Comparator가 필요한 것처럼 colllect()할 때는 Collector가 필요하다.</em></p>
<pre><code class="language-java">Object collect(Collector collector) </code></pre>
<h3 id="스트림을-컬렉션과-배열로-반환">스트림을 컬렉션과 배열로 반환</h3>
<ul>
<li><code>toList()</code>, <code>toSet()</code>, <code>toMap()</code>, <code>toCollection()</code>, <code>toArray()</code></li>
</ul>
<p>스트림의 모든 요소를 컬렉션에 수집하려면, Collectors 클래스의 <code>toList()</code>와 같은 메서드를 사용하면 된다.
특정 컬렉션을 지정하려면 <code>toCollection()</code>에 해당하는 컬렉션의 
생성자 참조를 매개변수로 넣어주면 된다.</p>
<pre><code class="language-java">ArrayList&lt;String&gt; list = names.stream().collect(Collectors.toCollection(toCollection(ArrayList::new));</code></pre>
<p>Map은 키와 값의 쌍으로 저장해야하니 객체의 어떤 필드를 키로 사용할지와 값으로 사용할지를 지정해줘야 한다.
아래 예제는 스트림에서 사람의 주민번호를 키로 하고, 값으로 Person 객체를 그대로 저장한다.</p>
<pre><code class="language-java">Map&lt;String, Person&gt; map  = personStream.collect(Collectors.toMap(p-&gt;p.getRegId(), p-&gt;p));</code></pre>
<h2 id="참고-자료">참고 자료</h2>
<ul>
<li>자바의 정석</li>
<li>윤성우의 열혈 자바 프로그래밍</li>
</ul>
<hr>
<p>자주 사용하던 스트림을 정리하니까 각 메소드의 사용 목적이 명확해졌다 🙃
또 Collector와 Collectors는 뭐가 다른지 궁금했는데 정리되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Exception에 대하여]]></title>
            <link>https://velog.io/@new_wisdom/Exception</link>
            <guid>https://velog.io/@new_wisdom/Exception</guid>
            <pubDate>Wed, 24 Feb 2021 04:14:42 GMT</pubDate>
            <description><![CDATA[<p>오늘 수업 시간에 자바의 Exception에 대해 배웠다.
수업을 듣고 들은 내용을 자바의 정석의 예외 처리를 함께 보면서 정리 ✍️</p>
<h2 id="프로그램-오류-종류">프로그램 오류 종류</h2>
<ul>
<li>컴파일 에러 - 컴파일 시에 발생하는 에러</li>
<li>런타임 에러 - 실행 시에 발생하는 에러</li>
<li>논리적 에러 - 실행은 되지만, 의도와 다르게 동작하는 것</li>
</ul>
<p>프로그램에서 실행 도중 발생할 수 있는 모든 경우의 수를 고려해 이에 대한 적절한 대비가 필요하다! </p>
<h3 id="error와-exception의-차이">Error와 Exception의 차이?</h3>
<h4 id="error">Error</h4>
<p>애플리케이션이 정상적으로 동작하는데 심각한 문제가 있는 경우 사용한다.
ex) 메모리 부족이나 스택오버플로우 등</p>
<p>개발자가 Error를 사용하는 일은 거의 없다고 한다.</p>
<h4 id="exception">Exception</h4>
<p>비즈니스 로직 상에서 에러가 발생하는 경우 사용한다. 
발생하더라도 수습이 가능하여 프로그래머가 이에 대한 적절한 처리를 할 수 있다.</p>
<h2 id="예외-클래스-계층-구조">예외 클래스 계층 구조</h2>
<p><img src="https://images.velog.io/images/new_wisdom/post/b3233d4f-d9e9-4c54-991b-5a0d24430cfb/pngwing.com.png" alt="">
모두 Throwable을 상속하고 있으며, 여기서부터 Error와 Exception이 발생한다.
여기서 모든 예외의 조상은 Exception 클래스이다.</p>
<p>또 예외 클래스들은 두 개의 그룹으로 나뉘어 질 수 있다.</p>
<ul>
<li>RuntimeException 클래스와 그 자손 클래스들</li>
<li>Exception 클래스와 그 자손 클래스들</li>
</ul>
<p>이 글에서는 RuntimeException 클래스와 그 자손 클래스들을 <strong>Checked Exception</strong>이라 하고,
Exception 클래스와 그 자손 클래스들을 <strong>Unchecked Exception</strong>이라고 하겠다.</p>
<h3 id="checked-exception">Checked Exception</h3>
<pre><code class="language-java">import lotto.view.ErrorView;

public class CustomException extends Exception {
    public CustomException() {
        ErrorView.printErrorMessage();
    }
}
</code></pre>
<p>...</p>
<pre><code class="language-java">
public class Application {
    public static void main(String[] args) throws CustomException {
        LottoNumber lottoNumber = LottoNumber.from(1);
    }
}</code></pre>
<p>Exception을 상속받아 사용하는 경우 컴파일 시점에 Exception을 확인할 수 있다. 
만약 컴파일 시점에 Exception에 대한 처리(try/catch)를 하지 않을 경우 컴파일 에러가 발생한다.
Exception이 발생하는 메소드에서 throws 예약어를 활용해 
Exception을 호출 메소드에 전달해야 한다.</p>
<p>상위 메서드로 throw를 던지는 행위는 상위 메서드들의 책임이 그만큼 증가하기 때문에,
그리 좋은 방법 같지는 않다.</p>
<h3 id="unchecked-exception">Unchecked Exception</h3>
<pre><code class="language-java">public class IllegalLottoNumberException extends IllegalArgumentException {
    public IllegalLottoNumberException() {
        ErrorView.printIllegalLottoNumberMessage();
    }
}</code></pre>
<p>...</p>
<pre><code class="language-java">public class LottoNumber implements Comparable&lt;LottoNumber&gt; {
    public static final int MIN_LOTTO_NUMBER = 1;
    public static final int MAX_LOTTO_NUMBER = 45;
    private static final Pattern NUMBER_PATTERN = Pattern.compile(&quot;^[0-9]*$&quot;);

    private final int value;

    public LottoNumber(String number) {
        validateLottoNumber(number);
        this.value = Integer.parseInt(number);
    }

    private void validateLottoNumber(String number) {
        if (isBlank(number) || isInvalidNumberFormat(number) || isInvalidLottoNumberRange(number)) {
            throw new IllegalLottoNumberException();
        }
    }</code></pre>
<p>Runtime Time Exception 이라고 한다.
컴파일 시점에 Exception이 발생할 것인지의 여부를 판단할 수 없다.
Exception이 발생하는 메소드에서 throws 예약어를 활용해 Exception을 처리할 필요가 없지만, 처리해도 무방하다.</p>
<h3 id="checked-exception-vs-unchecked-exception">Checked Exception VS Unchecked Exception</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>Checked Exception</th>
<th>Unchecked Exception</th>
</tr>
</thead>
<tbody><tr>
<td>확인 시점</td>
<td>컴파일타임</td>
<td>런타임</td>
</tr>
<tr>
<td>처리</td>
<td>반드시 예외 처리해야 한다.</td>
<td>throws를 통해 그냥 던져도, 처리해도 상관 없다.</td>
</tr>
<tr>
<td>대표 예외</td>
<td>IOException, SQLException</td>
<td>IllegalArgumentException, NullPointEception</td>
</tr>
</tbody></table>
<p>너무 치명적이면 Checked 쓰고,
굳이 경고가 필요없고, 서비스 코드를 만드는 입장이라면 최상단에서 
에러를 핸들링 할 수 있으니 Unchecked를 쓰는게 좋다.</p>
<p>참고로 코틀린에서는 Checked Exception은 코드만 늘어날 뿐이라 생각(?)해서 
여러가지 이유로... Checked Exception이 없다고 한다.
또 프로그래머 입장에서 메인과 같은 중앙에서 핸들링하는 녀석을 만들어 관리하는데,
굳이 우리가 Checked Exception을 제공할 필요가 있냐는 말이다.</p>
<p>수업시간에 다양한 말들로 둘을 구분지어 보았는데,
*<em>Checked Exception는 *</em></p>
<ul>
<li>내부 구현이 어떻게 되는지 알려주고 싶어!</li>
<li>내가 집 수리할건데 손 다칠수도 있으니까 구급차 미리 불러!</li>
<li>너 진짜 조심해야해!</li>
</ul>
<p>*<em>Unchecked Exception는 *</em></p>
<ul>
<li>내부에서 예외에 대한 방어가 있는데 클라이언트한테 공개는 안할거야, 대신 값을 잘 넣어주면 좋겠어.</li>
<li>내가 집 수리할건데 아냐 다치지 않고 잘 할 수 있어!</li>
<li>클라이언트가 입력할 값을 잘 알고 있겠지 ~</li>
</ul>
<p>이런 느낌으로 이야기가 나왔다.
Checked인지 Unchecked인지는 <strong>클라이언트에게 얼마나 책임을 떠넘기느냐</strong>에 대한 관점으로 봐도 좋을 것 같다.</p>
<h2 id="예외-처리---try-catch문">예외 처리 - try-catch문</h2>
<pre><code class="language-java">try {
    // 예외 발생 가능성 있는 문장들
} catch (Exception1 e1){
    // Exception1이 발생했을 경우, 처리하는 문장
} catch(Exception2 e2) {
    // Exception2가 발생했을 경우, 처리하는 문장
}</code></pre>
<p>이렇게 하나의 try 블럭 다음에는 여러 종류의 예외를 처리할 수 있도록
하나 이상의 catch 블럭이 올 수 있다.</p>
<h4 id="흐름">흐름</h4>
<p>try 블럭에서 예외가 발생하면, 예외가 발생한 위치 이후에 있는 
try 블럭의 문장들은 수행되지 않는다.
때문에 try 블럭에 포함시킬 코드의 범위를 잘 선택해야 한다.</p>
<p>예외가 발생하면 발생한 예외에 해당하는 클래스의 인스턴스가 만들어진다.
try블럭에서 예외가 발생되고, 첫 catch 문부터 차례대로 catch 블럭의
괄호 내 선언된 참조변수의 종류와 생성된 예외 클래스의 인스턴스에 <code>instanceof</code>연산자를 이용해 검사한다.
검사한 결과가 true인 블럭을 만날 때 까지 계속 검사한다.</p>
<h4 id="try에서-발생한-예외의-종류와-일치하는-단-하나의-catch-블럭만-수행된다">try에서 발생한 예외의 종류와 일치하는 단 하나의 catch 블럭만 수행된다.</h4>
<pre><code class="language-java">public class LottoNumber {
    private final int number;

    private LottoNumber(int number) {
        this.number = number;
    }

    public static LottoNumber from(final int number) throws CustomException {
        throw new CustomException();
    }
}</code></pre>
<p>다음과 같이 LottoNumber 객체를 <code>from()</code>으로 생성했을 때 
<code>Exception</code>을 상속받고 있는 <code>CustomException</code>을 발생시킨다고 해보자.
<img src="https://images.velog.io/images/new_wisdom/post/daa06d54-027d-44b4-aa16-4c4d985f3e72/image.png" alt=""></p>
<p>인텔리제이에서도 알 수 있듯이 <code>CustomException</code>의 상위 클래스인 
<code>Exception</code>을 미리 catch해주었기 때문에 하위 catch에서 
<code>CustomException</code>를 잡는 것은 소용이 없다.</p>
<p>모든 예외 클래스는 Exception 클래스의 자손이므로, 
Exception 클래스 타입의 참조변수를 선언하면 해당 블럭에서 어떤 예외던지 처리된다.
<img src="https://images.velog.io/images/new_wisdom/post/aae681e5-9d55-4e86-99fe-da67d1cf9492/image.png" alt=""></p>
<p>또 위와 같은 코드를 실행시켜보면 아래와 같은 출력 결과가 나온다.
<img src="https://images.velog.io/images/new_wisdom/post/20c67935-d673-4440-beb6-a943faf7d55d/image.png" alt=""></p>
<p><strong>멀티 catch 블럭</strong>
JDK1.7부터 catch 블럭을 <code>|</code>을 이용해 하나의 catch 쁠럭으로 합칠 수 있게 되었다.
<img src="https://images.velog.io/images/new_wisdom/post/0ae3a6dd-c32e-47ff-8d0c-9788613a410e/image.png" alt=""></p>
<p>하지만 이렇게 부모 자식 관계가 있다면 컴파일 에러가 발생한다.</p>
<h4 id="중첩된-try-catch">중첩된 try-catch</h4>
<p><img src="https://images.velog.io/images/new_wisdom/post/720fe0b3-6297-4a8e-85cb-4ad644451cd7/image.png" alt=""></p>
<p>하나의 메서드 안에 여러개의 try-catch를 사용할 수 있으며,
중첩으로도 사용이 가능하다.
하지만 catch블럭 괄호 내 참조 변수는 catch 블럭 내에서 유효한데,
위의 예제에서는 <code>e</code>의 참조변수의 영역이 서로 겹치기 때문에 컴파일 에러가 난다.</p>
<h2 id="custom-exception">Custom Exception</h2>
<p>기존에 정의된 예외 클래스 외에 필요에 따라 사용자 정의 클래스를 정의하여 사용할 수 있다.</p>
<pre><code class="language-java">class MyException extends Exception {
    MyException(String msg) {
        super(msg); 
    }
}</code></pre>
<p>생성시 string을 인자로 받아서 메시지로 저장할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Weekly 회고] 3주차 회고]]></title>
            <link>https://velog.io/@new_wisdom/%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%9A%8C%EA%B3%A0-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@new_wisdom/%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%9A%8C%EA%B3%A0-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 21 Feb 2021 13:43:46 GMT</pubDate>
            <description><![CDATA[<p>이제 매주마다 회고를 간략하게라도 작성하려 한다.
막상 주 단위로 회고를 작성하려니 이번주 뭔가 많은 걸 느꼈다고 생각하고
한 주를 돌아보며 몰아서 적으려 하니 어떤 걸 적으려 했는지 잘 기억이 안나는 것 같다 🥲</p>
<p>앞으로 매일 매일 어떤걸 공부했고, 어떤걸 느꼈는지 저장해놨다가 
주 단위로 업데이트를 해야겠다.</p>
<p>일단 이번주는 양식 없이, 내가 느낀 것들을 돌아보며 자유롭게 ✍️</p>
<h2 id="미션-시작-전까지">미션 시작 전까지</h2>
<p>화요일 새로운 미션이 시작되기 전까지는 자동차 경주 미션에서 받은 피드백들을 정리하고,
스스로 공부가 필요한 내용들은 블로그에 기록해나갔다.</p>
<p>아 그리고 주말에 읽었던 필독서 &quot;코딩을 지탱하는 기술&quot;을 읽고 느낀점을 정리했다.</p>
<h2 id="로또-미션-시작">로또 미션 시작</h2>
<h3 id="페어-프로그래밍-with-tdd">페어 프로그래밍 with TDD</h3>
<p>이번 미션이 시작되기 전 TDD 강의를 듣고 페어와 미션을 진행하게 되었다.
포비의 TDD 강의가 나에게는 굉장히 유익했다 !
&quot;TDD 이렇게 하는거 맞아..?&quot; 하는 나의 의문에 답할 수 있는 강의였다.</p>
<p>저번 미션에서 아쉬웠던 것은 페어와 구현 전부터 모든 설계를 완벽히 하기 위해
설계에 대해 엄청난 토론을 하느라 구현이 늦어진 점이다.
첫 페어 프로그래밍이라 그런지 그래도 대화를 통해 다른 인사이트를 얻을 수 있어서
유익한 시간이라고는 생각하지만, 설계하는데 많은 에너지를 쏳은 것 같았고
또 구현하다보니 설계도 많이 바뀌게 됨을 경험했다.</p>
<p>이번 페어와는 TDD 강의대로 </p>
<ul>
<li>처음부터 완벽함을 추구하지 말고, 일단 구현부터!</li>
<li>테스트 가능한 부분을 찾고 도메인을 만들어 나가자!</li>
<li>한가지 일에만 집중하자!</li>
</ul>
<p>이 말들을 계속 상기시키며 미션을 진행했다.
나도 사실 완벽한 설계가 없는 상태에서 구현에 들어가는게 낯설고
계속해서 구현하다가 다른 고민해볼 거리가 생기면 그것을 파고드는 경향이 있는데,
다행히 페어가 그럴때마다 샛길로 새지 않게 잘 잡아준 것 같다.
서로가 한 가지 일이 아닌 다른 기능을 논하려 할 때 저 말들을 상기시켜주면서
샛길로 새지 않도록 도왔다.</p>
<p>그랬더니 정말 신기하게도, 내 생각보다 구현이 빨리 끝났던 것 같다.
페어와 <strong>&quot;일단 시도해보자&quot;</strong> 이 마인드를 계속 상기시켰던 것이 우리가 제시간 안에
구현을 마칠 수 있었던 이유였던 것 같다.</p>
<p>이번 미션으로 TDD의 많은 이점을 느끼게 된 것 같다.
강의에서 들었던 대로 아래와 같은 이점들을 페어와 함께 느낄 수 있었다.</p>
<ul>
<li>수정 사항이 생겨도 테스트를 통과한다면 마음의 안정</li>
<li>핵심 비지니스 로직 구현에 집중하면서 학습 효율이 높아짐을 느낌</li>
<li>구현, 설계 시간 단축</li>
<li>객체 설계에 도움이 됨</li>
</ul>
<p>TDD를 나혼자 시도한 것이 아니라 페어와 함께 시도했기 때문에 더 든든했던 것 같다.
페어 프로그래밍을 할 때 마다 매번 많은 이점을 얻어간다.</p>
<h3 id="새로운-학습-로그">새로운 학습 로그</h3>
<p>로또 미션이 시작 되는 화요일, 
강의 전에 학습 로그라는 새로운 교육 제도를 도입한다고 하셨다.</p>
<p>매 리뷰 요청마다 이번 미션에서 자신이 어떤 것을 배우고 깨달았는지 한 눈에 
볼 수 있도록 기록하는 것이다.</p>
<p>학습로그, 조금은 생소했으나
나는 내가 배우고 깨달은 것을 정리하는 것이 내게 필요하기도 하고,
좋아하기도 해서 굉장히 유용한(?) 제도라고 생각했다.</p>
<p>하지만 페어 프로그래밍을 진행하면서 
첫 PR을 목요일 18시까지 해야했기 때문에 미션을 완성하고 학습로그까지
적어내는 것은 빠듯하지 않을까 걱정이 되기도 했다.</p>
<p>그래서 페어 프로그래밍이 시작되고,
페어와 만나는 오전 10시 전부터 내가 배운 점들을 미리 기록해나갔다.
또 페어와 함께 미션이 마무리 되고, 
함께 간단한 회고를 진행하면서
&quot;이번에 미션에서 이런 개념을 사용했는데, 우리가 이런 개념을 적용한 이유가 뭘까?&quot; 
하면서 서로 어떤 기술을 사용했던 명분을 돌이켜보았다.
이것이 학습 로그를 작성하는데 큰 도움이 되었던 것 같다.</p>
<p>요즘 어떤 요구사항이나 개념을 던져주었을 때,
그것을 왜 써야 하는지, 왜 필요한지를 계속 스스로 물어가며 답을 찾는 방법으로 학습하고 있다.
이렇게 되니 미션의 모든 요구사항에 물음표를 던져 세세한 부분에 너무 집중하고 있는 것인가 하는 의문이 들기도 하지만, 
나는 아직 자바 초보고, 분명 요구사항으로 주어지는 이유가 있다고 생각하기 때문에 
계속해서 모든 것에 물음표를 던지려 노력하고 있다.</p>
<h2 id="나">&#39;나&#39;</h2>
<h3 id="아침-일찍-일어나기">아침 일찍 일어나기</h3>
<p>우테코가 시작되고 &quot;미라클 모닝&quot; 비스무리하게 스스로 아침 일찍 일어나기 챌린지를 하고 있다.
내가 이를 시작하게 된 이유는 몇 가지가 있다.</p>
<ul>
<li>나만의 시간을 지키기 위해서</li>
<li>집중이 잘 되는 시간을 이용해 공부하기 위해서</li>
<li>우테코 시작에 좀 더 여유로운 마음으로 참여하기 위해(?)</li>
</ul>
<p>이번주도 계속 6-7시에 일어났는데,
덕분에 나의 개인적 학습 시간을 확보할 수 있었다.
아침에 리프레시된 상태로 학습을 하니 효율성도 확실히 높아 지는 장점을 느끼고 있다.</p>
<p>아침 일찍 일어나기로 생활 패턴을 바꾼 것은 정말 좋은 선택이라 생각한다.</p>
<p>그런데 이번주 잠을 좀 모자라게 잤더니 주말에 잠이 늘어버렸다 🥲
이번주는 체력관리를 잘해야지.</p>
<h3 id="부족함을-인정했다">부족함을 인정했다.</h3>
<p>사실 이 부분이 이번주 나한테 굉장히 큰 변화(?)였는데,
우테코가 시작되고 그 당시에는 몰랐으나 나는 굉장히 긴장한 상태였던 것 같다.</p>
<p>뛰어난 실력을 가진 사람들 안에서 내가 있어도 되는 걸까,
나만 출발이 늦은 것 같고, 나도 부단히 공부하고 있는 것 같은데
다른 사람이 공부하는 수준보다 떨어진다고 스스로 좌절시키고 있었다.
때문에 그 당시에는 잘 몰랐지만, 학습하는 것이 즐겁기보다는 벅차다고 느꼈던 것 같다.</p>
<p>하지만 이 마인드를 바꿀 수 있었던 것은 
우테코에서는 계속해서 이는 당연한 것이라고 말해주었다.</p>
<pre><code>사람마다 출발선이 다를 수 있다.
나만 그런 것 같다고 느끼는 것 같겠지만 여기있는 대부분의 사람들이 
이를 느끼고 있을 것이다. 
모른다는 것, 느리다는 것을 부끄러워 하지말라.</code></pre><p>이 말들이 나에게 굉장히 위로가 되었고 도전이 되었다.
몰라서 교육을 받게 된 것이고, 이는 당연한 것이다.
모르는 것을 숨기면 성장할 수 있는가 ? 
모르는 것을 발견하고 드러낼 때 그 빈틈이 채워진다.</p>
<p>우테코에서는 경쟁하라고 하지 않는다.
이 교육 철학이 나에게 큰 힘이 되는 것 같다.
&quot;남과의 경쟁 아닌 어제의 나와 경쟁하라&quot;
이 말을 이제서야 몸소 깨달은 것 같다.
나도 이제 나와의 경주를 시작할 것이다.</p>
<p>이랬더니 정말 이번 한주 학습하는 것이 여유로워졌다.
나 스스로와 경쟁하니 배움의 즐거움이 생겼고, 
매일 성장하는 나를 기대하게 되었다.</p>
<p>이 마인드를 얻게 된 것은 굉장히 큰 변화이다.</p>
<p>회고를 쓰다보니 주절주절 써버린 것 같은데, 글쓰는 연습을 많이 해야할 것 같다.
일단 이번주는 자유롭게, 여기까지!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Enum 열거형]]></title>
            <link>https://velog.io/@new_wisdom/Java-Enum-%EC%97%B4%EA%B1%B0%ED%98%95</link>
            <guid>https://velog.io/@new_wisdom/Java-Enum-%EC%97%B4%EA%B1%B0%ED%98%95</guid>
            <pubDate>Sun, 21 Feb 2021 11:31:16 GMT</pubDate>
            <description><![CDATA[<h2 id="열거형이란">열거형이란?</h2>
<p>JDK 1.5 부터 새로 추가된 개념이다.</p>
<p>기존의 언어들과 자바의 Enum이 다른 점은</p>
<ul>
<li>열거형이 갖는 값 뿐만 아니라 타입까지 관리하기 때문에 보다 
논리적인 오류를 줄일 수 있다.</li>
<li>&#39;타입에 안전한 열거형&#39;을 제공하여 실제 값이 같아도 타입이 다르면 조건식 결과가 false이다. 값 뿐만 아니라 타입까지 체크한다.</li>
<li>상수 값이 바뀌어도 기존 소스를 다시 컴파일하지 않아도 된다. </li>
</ul>
<h3 id="열거형의-정의와-사용">열거형의 정의와 사용</h3>
<pre><code class="language-java">enum 열거형이름 {상수명1, 상수명2, ...}</code></pre>
<p>열거형에 정의된 상수를 사요아는 방법은 <code>열거형이름.상수명</code>이다.
클래스의 static 변수를 참조하는 것과 동일하다.</p>
<h4 id="열거형-상수간-비교">열거형 상수간 비교</h4>
<p><code>==</code> 연산자를 사용하여 비교할 수 있다.
<code>equals()</code>가 아닌 <code>==</code>으로 비교가 가능하다는 것은 그만큼 성능이 좋다는 것이다.
<code>&lt;, &gt;</code>로는 비교할 수 없지만 <code>compareTo()</code>는 사용이 가능하다.</p>
<p>또 <code>switch</code> 문의 조건식에도 사용할 수 있다.</p>
<pre><code class="language-java">switch(d1) {
    case EAST: // Direction.EAST라고 쓰면 안된다.
        System.out.println(&quot;The direction is EAST.&quot;); 
        break;
    case SOUTH:
        System.out.println(&quot;The direction is SOUTH.&quot;); 
        break;
    case WEST:
        System.out.println(&quot;The direction is WEST.&quot;); 
        break;
    case NORTH:
        System.out.println(&quot;The direction is NORTH.&quot;); 
        break;
    default:
        System.out.println(&quot;Invalid direction.&quot;); 
        break;
    }</code></pre>
<h4 id="다양한-메소드">다양한 메소드</h4>
<p>열거형에 정의된 모든 상수를 출력하려면 다음과 같이 한다.</p>
<pre><code class="language-java">Direction[] dArr = Direction.values();

for(Direction d : dArr ) 
    System.out.printf(&quot;%s=%d%n&quot;, d.name(), d.original());</code></pre>
<ul>
<li><code>values()</code> : 열거형의 모든 상수를 배열에 담아 반환한다.</li>
<li><code>ordinal()</code> : 모든 열거형의 조상인 <code>java.lang.Enum</code> 클래스에 정의된 것으로, 정의된 순서를 정수로 반환한다.</li>
<li><code>name()</code> : 열거형 상수의 이름을 문자열로 반환한다.</li>
<li><code>valueOf()</code> : 지정된 열거형에서 name과 일치하는 열거형 상수를 반환한다.</li>
</ul>
<h3 id="열거형의-생성자">열거형의 생성자</h3>
<p>Enum 타입은 열거형을 의미하는 특별한 형태의 클래스이기 때문에 일반 클래스와 같이
생성자가 존재하여애 한다. 자바가 기본 생성자를 만들어주긴 하지만, 
열거형의 생성자는 제어자가 묵시적으로 private으로 지정해줘야 한다.</p>
<p>이유는 고정된 상수의 집합으로 런타임이 아닌 컴파일 타임에 모든 값을 
알고 있어야 하기 때문이다.
즉, 다른 패키지나 클래스에서 접근해 동적으로 값을 할당할 수 없다.</p>
<h3 id="열거형에-멤버-추가하기">열거형에 멤버 추가하기</h3>
<p><code>oridinal()</code>이 열거형 상수가 정의된 순서를 반환하지만, 
내부적인 용도로만 사용되기 위한 것이기 때문에 열거형 상수의 값으로 사용하지 않는 것이 좋다.</p>
<p>열거 상수의 값이 불규칙적인 경우에는 다음과 같이 열거형 상수 이름 옆에 
원하는 값을 괄호와 함께 적어준다.
그리고 지정된 값을 저장할 수 있는 인스턴스 변수와 생성자를 새로 추가해주어야 한다.</p>
<pre><code class="language-java">enum Direction {
    EAST(1), SOUTH(5), WEST(-1), NORTH(10);

    private final int value; // 정수를 저장할 필드(인스턴스 변수) 추가
    Direction(int value) {this.value = value;}

    public int getValue() {return value;}
}</code></pre>
<p>필요에 따라 하나의 열거형 상수에 여러 값을 지정할 수 있다.
이에 맞게 인스턴스 변수와 생성자 등을 새로 추가해주어야 한다.</p>
<pre><code class="language-java">enum Direction {
    EAST(1, &quot;&gt;&quot;), SOUTH(5, &quot;V&quot;), WEST(-1, &quot;&lt;&quot;), NORTH(10, &quot;^&quot;);

    private final int value; // 정수를 저장할 필드(인스턴스 변수) 추가
    private final String symbol;
    Direction(int value, String symbol) {
        this.value = value;
        this.symbol = symbol;
    }

    public int getValue() {return value;}
    public String getSymbol() {return symbol;}</code></pre>
<h4 id="example">Example</h4>
<pre><code class="language-java">enum Direction { 
    EAST(1, &quot;&gt;&quot;), SOUTH(2,&quot;V&quot;), WEST(3, &quot;&lt;&quot;), NORTH(4,&quot;^&quot;);

    private static final Direction[] DIR_ARR = Direction.values();
    private final int value;
    private final String symbol;

    Direction(int value, String symbol) { // private Direction(int value)
        this.value  = value;
        this.symbol = symbol;
    }

    public int getValue()      { return value;  }
    public String getSymbol()  { return symbol; }

    public static Direction of(int dir) {
        if (dir &lt; 1 || dir &gt; 4) {
            throw new IllegalArgumentException(&quot;Invalid value :&quot; + dir);
        }
        return DIR_ARR[dir - 1];        
    }    

    // 방향을 회전시키는 메서드. num의 값만큼 90도씩 시계방향으로 회전한다.
    public Direction rotate(int num) {
        num = num % 4;

        if(num &lt; 0) num +=4; // num이 음수일 때는 시계반대 방향으로 회전 

        return DIR_ARR[(value-1+num) % 4];
    }

    public String toString() {
        return name()+getSymbol();
    }
} // enum Direction

class EnumEx2 {
    public static void main(String[] args) {
        for(Direction d : Direction.values()) 
            System.out.printf(&quot;%s=%d%n&quot;, d.name(), d.getValue()); 

        Direction d1 = Direction.EAST;
        Direction d2 = Direction.of(1);

        System.out.printf(&quot;d1=%s, %d%n&quot;, d1.name(), d1.getValue());
        System.out.printf(&quot;d2=%s, %d%n&quot;, d2.name(), d2.getValue());

        System.out.println(Direction.EAST.rotate(1));
        System.out.println(Direction.EAST.rotate(2));
        System.out.println(Direction.EAST.rotate(-1));
        System.out.println(Direction.EAST.rotate(-2));
    }
}</code></pre>
<h3 id="열거형에-추상-메서드-추가하기">열거형에 추상 메서드 추가하기</h3>
<h4 id="example-1">Example</h4>
<pre><code class="language-java">enum Transportation { 
    BUS(100)      { int fare(int distance) { return distance*BASIC_FARE;}},
    TRAIN(150)    { int fare(int distance) { return distance*BASIC_FARE;}},
    SHIP(100)     { int fare(int distance) { return distance*BASIC_FARE;}},
    AIRPLANE(300) { int fare(int distance) { return distance*BASIC_FARE;}};

    protected final int BASIC_FARE; // protected로 해야 각 상수에서 접근가능

    Transportation(int basicFare) { // private Transportation(int basicFare) {
        BASIC_FARE = basicFare;
    }

    public int getBasicFare() { return BASIC_FARE; }

    abstract int fare(int distance); // 거리에 따른 요금 계산
}

class EnumEx3 {
    public static void main(String[] args) {
        System.out.println(&quot;bus fare=&quot;     +Transportation.BUS.fare(100));
        System.out.println(&quot;train fare=&quot;   +Transportation.TRAIN.fare(100));
        System.out.println(&quot;ship fare=&quot;    +Transportation.SHIP.fare(100));
        System.out.println(&quot;airplane fare=&quot;+Transportation.AIRPLANE.fare(100));
    }
}</code></pre>
<p>Transportation은 운송 수단의 종류 별로 상수를 정의하고 있고,
각 운송 수단에는 기본요금이 책정되어 있다.
여기서 거리에 따라 요금을 계산하는 방식이 각 운송 수단마다 다른 경우를 위해,
추상 메서드 <code>fare(int distance)</code>를 선언해 각 열거형 상수가 이 추상 메서드를 반드시 구현해야 한다.</p>
<p>열거형에 추상 메서드를 선언할 일은 그리 많지 않다.</p>
<h3 id="열거형의-비교">열거형의 비교</h3>
<pre><code class="language-java">enum Direction { EAST, SOUTH, WEST, NORTH; }</code></pre>
<p>이 열거형 상수 하나하나가 Direction 객체이다. 
Direction 클래스의 static 상수 EAST, SOUTH, WEST, NORTH의 값은 객체의 주소이고,
이 값은 바뀌지 않는 값이므로 <code>==</code>로 비교가 가능하다.</p>
<h4 id="example-2">Example</h4>
<pre><code class="language-java">abstract class MyEnum&lt;T extends MyEnum&lt;T&gt;&gt; implements Comparable&lt;T&gt; {
    static int id = 0;

    int ordinal;
    String name = &quot;&quot;;

    public int ordinal() { return ordinal; }

    MyEnum(String name) {
        this.name = name;
        ordinal = id++;    
    }

    public int compareTo(T t) {
        return ordinal - t.ordinal();
    }
}</code></pre>
<p>객체가 생성될 때마다 번호를 붙여서 인스턴스 변수 ordinal에 저장한다.
그리고 Comparable 인터페이스를 구현해서 열거형 상수간의 비교가 가능하도록 되어 있다.</p>
<p>만일 클래스를 <code>MyEnum&lt;T&gt;</code>와 같이 선언하였다면, compareTo()를 위와 같이
간단히 작성할 수 없었을 것이다.
타입 T에 <code>ordinal()</code>이 정의되어 있는지 확인할 수 없기 때문이다.
그래서 <code>MyEnum&lt;T extends&lt;MyEnum&lt;T&gt;&gt;</code>와 같이 선언한 것이며,
이것은 타입 T가 <code>MyEnum&lt;T&gt;</code>의 자손이어야 한다는 의미이다.
타입 T가 MyEnum의 자손이므로 ordinal()이 정의되어 있는 것은 분명하므로,
형변환 없이도 에러가 나지 않는다.</p>
<p>그리고 추상 메서드를 새로 추가하면, 클래스 앞에도 abstract를 붙여줘야 하고,
각 static 상수들도 추상 메서드를 구현해주어야 한다.</p>
<h3 id="참고-자료">참고 자료</h3>
<ul>
<li>자바의 정석 3판</li>
<li><a href="https://www.nextree.co.kr/p11686/">Java: enum의 뿌리를 찾아서</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[강의] Level 1. TDD 강의 정리]]></title>
            <link>https://velog.io/@new_wisdom/02.16-%EA%B0%95%EC%9D%98</link>
            <guid>https://velog.io/@new_wisdom/02.16-%EA%B0%95%EC%9D%98</guid>
            <pubDate>Sat, 20 Feb 2021 13:27:41 GMT</pubDate>
            <description><![CDATA[<p>이번 로또 미션을 구현하면서 페어와 TDD를 연습하면서
강의에서 들었던 모든 이점들을 느낄 수 있었다.</p>
<p>사실 완벽하게 TDD를 진행했다고 자신할 수 없으나,
강의 내용에서 들었던 이점들을 페어와 함께 TDD를 진행하면서 경험할 수 있었다.</p>
<p>여기서는 TDD 강의 내용을 들으면서 정리한 것을 조금 가공해서 정말 간단히 기록한다 ✍️</p>
<h2 id="tdd-리팩토링이란">TDD, 리팩토링이란?</h2>
<h3 id="tddtest-driven-development---테스트-주도-개발">TDD(Test Driven Development) - 테스트 주도 개발</h3>
<h4 id="프로덕션-코드">프로덕션 코드</h4>
<p>프로그램 구현을 담당하는 코드</p>
<h4 id="테스트-코드">테스트 코드</h4>
<p>프로덕션 코드가 정상적으로 동작하는지 확인하는 코드</p>
<h3 id="tdd란">TDD란?</h3>
<p>일반적으로는 프로덕션 먼저 구현 후 테스트 였는데
이건 테스트를 먼저 한 후 프로덕션을 개발한다.</p>
<h4 id="testfirstdevelopment--리팩토링">TestFirstDevelopment + 리팩토링</h4>
<p>테스트 코드를 만들고 프로덕션 후 리팩토링
리팩토링은 기능은 추가하지 않지만 설계를 변경하면서 
유지보수 용이, 가독성을 챙긴다.</p>
<p>설계를 한번에 몰아서 하는게 아니라 작은 단위로 자주하자.
리팩토링은 설계일 수도 있고 다양한데 그 과정을 자주하자는 것.</p>
<blockquote>
<p>TDD는 분석 기술이며, 설계 기술이기도 하다. - 켄트벡, Test Driven Development by Example 중</p>
</blockquote>
<p>todo-list를 잘 작성하는게 요구사항 분석이다.
디버깅 시간이 줄어든다.</p>
<h3 id="tdd-사이클">TDD 사이클</h3>
<ul>
<li>실패 테스트 구현</li>
<li>테스트 성공하도록 프로덕션 구현</li>
<li>프로덕션 코드와 테스트 코드 리팩토링</li>
</ul>
<h3 id="tdd-원칙">TDD 원칙</h3>
<ul>
<li>원칙 1 - 실패하는 단위 테스트를 작성할 때까지 프로덕션 코드를 작성하지 않는다.</li>
<li>원칙 2 - 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.</li>
<li>원칙 3 - 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.</li>
</ul>
<p><strong>무조건 실패 테스트를 본 후 프로적션 코드를 작성한다.</strong></p>
<h3 id="tdd-이점">TDD 이점</h3>
<h4 id="마음의-편안">마음의 편안</h4>
<p>요구사항 수정에 소스 코드를 수정하고, 불안해하지 않는다.</p>
<h4 id="한번에-한가지에-집중">한번에 한가지에 집중</h4>
<p>TDD 없이 개발하다 보면 상당히 머리로 상당히 많은 로직을 짜야하는데
천재개발자가 아닌 이상 어렵다.
한번에 한가지만 집중할 수 있다.</p>
<p>실패 테스트 만들고 패스를 하면 
그 다음 입력과 출력에 집중,  로직 구현 집중, 테스트 통과 위한 어떠한 행위 허용.</p>
<p>대부분의 개발자들은 동시에 같이 하려고 한다.
복잡한 요구사항에서 설계를 고민하면 굉장히 어렵다.
<strong>처음부터 완벽한 설계를 하는 것이 아니라, 점진적으로 설계를 개선할 수 있다.</strong></p>
<h4 id="빠른-피드백">빠른 피드백</h4>
<p>초반에는 피드백에 시간이 좀 걸리지만 점차 버그를 찾는 시점이 빨라진다.</p>
<h4 id="서비스-안정성이-높아짐">서비스 안정성이 높아짐</h4>
<p>버그 발생 가능성이 줄고, 코드 품질 향상</p>
<h4 id="개발자-역량-강화">개발자 역량 강화</h4>
<p>학습 효율 높아짐, 핵심 비지니스 로직 구현에 집중</p>
<p>구현이 완성되면 심리적 안정감이 생겨 창의력이 생김
<strong>구현부터!!!!!</strong>
설계부터 하면 압박감 때문에 잘 못함 설계를 고민하지 않아도 된다.</p>
<p>완벽한 설계에 많은 시간을 투자하면 나중에 변경될 때 아까워서 집착한다.
소프트웨어는 말랑말랑~</p>
<p>➕ 기능 추가 삭제 변경 빼고는 리팩토링이다
리팩토링은 새로운 테스트 케이스가 추가되지 않아야 한다.</p>
<p>내가 할 수 있는 부분까지만 설계 (초반 설계 조금)하고 TDD를 해야한다.</p>
<p><em>❓ 기능 단위 하나 -&gt; test -&gt; 구현 / 전체 test -&gt; 구현 ?</em>
선호하는 방식을 찾아라 ~</p>
<p><em>❓ 설계는 실제 클래스 구현으로 볼 수 있는지? 아니면 따로 문서로 정리한 것을 설계로 볼 수 있는지?</em>
UML이라는 클래스 설계가 있다.
여러가지 다이어그램이 있는데 요구사항 복잡도에 따라 다이어그램 있는게 좋다.
별도의 문서 (다이어그램)이 있는게 좋다.</p>
<p>TDD 이게 맞나? 긴가민가하겠지만 &quot;원래 처음에 경험하는 거다 이런거~ 당연한 거임&quot;</p>
<p>&quot;계속 도전할 것이 있어야 즐거운 것&quot;</p>
<h4 id="어디서-어떻게-시작해야할지-모르겠다">어디서 어떻게 시작해야할지 모르겠다</h4>
<p>이때 요구사항 분석 및 설계를 하라</p>
<ul>
<li>객체 추출</li>
<li>핵심 도메인 영역 집중 설계</li>
</ul>
<p>Controller와 View는 아직, 도메인 설계에 집중해라.
도메인에 대한 테스트 코드를 먼저 만들어라</p>
<h2 id="자동차-tdd">자동차 TDD</h2>
<h4 id="테스트-가능한-부분-찾아-단위-테스트">테스트 가능한 부분 찾아 단위 테스트</h4>
<h4 id="테스트하기-어려운-부분-찾아-가능한-구조로-개선">테스트하기 어려운 부분 찾아 가능한 구조로 개선</h4>
<ul>
<li>랜덤 값에 따라 전진</li>
</ul>
<p>이럴 때는 오브젝트 그래프에서 의존 관계를 가지지 않는 마지막 노드를 먼저 찾는다. 
이게 아무런 의존 관계가 없는...
그럼 이게 테스트 하기 쉽다면 전체가 테스트 쉽다. 
테스트 영역이 많아진다. </p>
<p>마지막 노드가 테스트하기 쉬워야 한다.
어려우면 전체에서도 테스트 영역이 줄어든다.
테스트하기 어려운 의존 관계를 상위로 끌어 올리자.
그렇지만 언젠가는 테스트하기 어려운 코드는 나올 수 있다. </p>
<p><em>❓ 테스트 어려운 노드 최대한 상위로? 아니면 적절 단계에서 멈춤?</em>
무조건 최상위가 아닌 적정한 단계 까지만이 좋다.</p>
<h3 id="tdd-과정">TDD 과정</h3>
<p>TDD는 작은 단위로 시작해야지 편하다.</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/4610d976-318c-4aea-8732-e18386ca5256/image.png" alt="">
컴파일 에러를 해결하기 위해 클래스, 메소드 만든다 .
(맥 기준 옵션 + 엔터)</p>
<p>포비는 한 메소드를 완벽히 구현 했을 때 커밋한다.
컴파일 안되는 건 커밋하지 말자.
커밋하고 리팩토링 연습 해도 됨.
테스트 코드에 대한 리팩토링도필요하다.</p>
<p>이때 설계를 고민해라.
여기서 move가 랜덤 값에 의존하지 않도록 랜덤 값을 받는 방식으로 바꾸자!
사실 이렇게 생각하는게 쉽지는 않음 그러면 리팩토링할게 생각나고 이럼 ㅋ</p>
<p>리팩토링은 테스트케이스 변경이 없다!</p>
<p><img src="https://images.velog.io/images/new_wisdom/post/2159ebca-ad63-4233-9ee6-8c424b2fa19c/image.png" alt="">
필드로 중복되는거는 이렇게 빼자</p>
<p><em>❓ 프로덕션 작성하면서 리팩토링 보이면 일단 참고 테스트하고 리팩토링?</em>
TDD는 한번에 한가지만 집중이니까 보인다면 문서에 일단 적어두자!
TDD는 todo를 만들어라</p>
<ul>
<li>todo</li>
<li>done</li>
</ul>
<p>TDD를 하다보면 설계가 완전히 달라질 수 있다.</p>
<p>(메서드 추출 단축키 : 옵션 + 커맨드 + m)</p>
<p>어떻게 테스트 가능하게 만드나?
고민하다 보면 기존 설계와는 완전히 다른게 나올 수 있다.
랜덤 배열을 전달할수도 있고. . . 
여러 설계를 고민할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective java] item 34. int 상수 대신 열거 타입을 사용하라]]></title>
            <link>https://velog.io/@new_wisdom/Effective-java-item-34.-int-%EC%83%81%EC%88%98-%EB%8C%80%EC%8B%A0-%EC%97%B4%EA%B1%B0-%ED%83%80%EC%9E%85%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@new_wisdom/Effective-java-item-34.-int-%EC%83%81%EC%88%98-%EB%8C%80%EC%8B%A0-%EC%97%B4%EA%B1%B0-%ED%83%80%EC%9E%85%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</guid>
            <pubDate>Sat, 20 Feb 2021 12:14:05 GMT</pubDate>
            <description><![CDATA[<h2 id="enum-">Enum ?</h2>
<p><a href="https://velog.io/@new_wisdom/Java-Enum-%EC%97%B4%EA%B1%B0%ED%98%95">[Java] Enum 열거형</a></p>
<h2 id="int-enum-pattern의-단점">int Enum Pattern의 단점</h2>
<h3 id="타입-안전을-보장할-방법이-없다">타입 안전을 보장할 방법이 없다.</h3>
<pre><code class="language-java">public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;</code></pre>
<p>위와 같은 예제에서는 사과용 상수 이름은 모두 <code>APPLE_</code>로 시작,
오렌지용 상수는 <code>ORANGE_</code>로 시작한다.
이는 표현력이 좋지 않다.
자바가 정수 열거 패턴을 위한 별도 이름 공간을 지원하지 않는다.</p>
<h3 id="프로그램이-깨지기-쉽다">프로그램이 깨지기 쉽다.</h3>
<p>평범한 상수를 나열한 것뿐이라 컴파일하면 그 값이 클라이언트 파일에 그대로 새겨진다.
상수의 값이 바뀌면 클라이언트도 반드시 다시 컴파일해야 한다.</p>
<h3 id="문자열로-출력하기-까다롭다">문자열로 출력하기 까다롭다.</h3>
<p>값을 출력하거나 디버거로 살펴보면 단지 숫자로만 보여서 썩 도움이 되지 않는다.
같은 정수 열거 그룹에 속한 모든 상수를 순회하는 방법도 마땅하지 않다.
또 이 안에 상수가 몇 개인지도 알 수 없다.</p>
<h4 id="정수-대신-문자열-상수를-사용하는-변형-패턴은">정수 대신 문자열 상수를 사용하는 변형 패턴은?</h4>
<p>더 나쁘다.
상수의 의미를 출력할 수 있다는 점은 좋지만,
문자열 상수릐 이름 대신 문자열 값을 그대로 하드코딩하게 만들기 떄문이다.
문자열에 오타가 있어도 컴파일러는 확인할 길이 없으니 자연스럽게 런타임 버그가 생긴다.
또 문자열 비교는 비교적 성능 저하를 일으킨다. </p>
<h2 id="열거-타입enum">열거 타입(Enum)</h2>
<pre><code class="language-java">public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}</code></pre>
<p>C, C++ 같은 다른 언어의 열거 타입과 다른 점은 자바의 열거 타입은 완전한 형태의 클래스다.</p>
<p>열거 타입 자체는 클래스며, 상수 하나당 자신의 인스턴스를 하나씩 만들어 
<code>public static final</code> 필드로 공개한다.
열거 타입은 밖에서 접근할 수 있는 생성자를 제공하지 않으므로 사실상 final이다.
따라서 클라이언트가 인스턴스를 직접 생성하거나 확장할 수 없으니 열거 타입 선언으로 
만들어진 인스턴스들은 딱 하나씩만 존재함이 보장된다.
즉 열거 타입은 인스턴스 통제된다. 
싱글턴은 원소가 하나뿐인 열거타입이라 할 수 있고, 
열거 타입은 싱글턴을 일반화한 형태라고 볼 수 있다.</p>
<h3 id="컴파일타임-타입-안정성-제공">컴파일타임 타입 안정성 제공</h3>
<pre><code class="language-java">public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}</code></pre>
<p>위 코드에서 Apple의 열거 타입을 매개변수로 받는 메서드를 선언했다면,
건네받은 참조는 Apple의 세 가지 값 중 하나임이 확실하다.
다른 타입의 값을 넘기려 하면 컴파일 오류가 난다.
타입이 다른 열거 타입 변수에 할당하려 하거나 
다른 열거 타입의 값 끼리 <code>==</code> 연산자로 비교하려는 꼴이기 때문이다.</p>
<h3 id="각자의-이름-공간이-존재한다">각자의 이름 공간이 존재한다.</h3>
<p>때문에 이름이 같은 상수도 평화롭게 공존한다.
열거 타입에 새로운 상수를 추가하거나 순서를 바꿔도 다시 컴파일 하지 않아도 된다.
열거 타입에 새로운 상수를 추가하거나 순서를 바꿔도 다시 컴파일 하지 않아도 된다.
공개되는 것이 오직 필드의 이름뿐이니 ,
정수 열거 패턴과 달리 상수 값이 클라이언트로 컴파일 되어 각인되지 않기 때문이다.</p>
<h3 id="문자열로-출력하기-적합하다">문자열로 출력하기 적합하다.</h3>
<p>열거타입의 <code>toString()</code>은 출력하기에 적합한 문자열을 내어준다.</p>
<h3 id="임의의-메서드-필드를-추가하고-임의의-인터페이스를-구현할-수도-있다">임의의 메서드, 필드를 추가하고 임의의 인터페이스를 구현할 수도 있다.</h3>
<p><code>Object</code> 메서드들을 높은 품질로 구현해놨고, <code>Comparable</code>과 <code>Serializable</code>을 
구현했으며, 그 직렬화 형태도 웬만큼 변형을 가해도 문제없이 동작하게끔 구현해놨다.</p>
<h2 id="열거-타입-사용-경우">열거 타입 사용 경우</h2>
<h3 id="각-상수와-연관된-데이터를-해당-상수-자체에-내재시킬-때">각 상수와 연관된 데이터를 해당 상수 자체에 내재시킬 때</h3>
<p>예제로 들었던 Apple과 Orange에 과일 색을 알려주거나, 과일 이미지를 반환하는 메서드를 추가한다면, 열거 타입에 이 기능을 메서드로 추가할 수 있다.</p>
<p>가장 단순하게는 그저 상수의 모음일 뿐인 열거 타입이지만, 
고차원의 추상 개념 하나를 완벽히 표현해낼 수도 있다.</p>
<h4 id="example">Example</h4>
<p>태양개의 행성에는 각각 질량과 반지름이 있고, 이 두 속성을 이용해 표면중력을 계산할 수 있다.
따라서 어떤 객체의 질량이 주어지면 그 객체가 행성 표면에 있을 때의 무게도 계산할 수 있다.
표면 중력을 계산해 저장한 이유는 단순히 최적화를 위해서다.</p>
<pre><code class="language-java">@Getter
public enum Planet {
    MERCURY(3.302e+23, 2.439e6),
    VENUS(4.869e+24, 6.052e6),
    EARTH(5.975e+24, 6.378e6),
    MARS(6.419e+23, 3.393e6),
    JUPITER(1.899e+27, 7.149e7),
    SATURN(5.685e+26, 6.027e7),
    URANUS(8.683e+25, 2.556e7),
    NEPTUNE(1.024e+26, 2.447e7);

    private final double mass;            // 질량(단위: 킬로그램)
    private final double radius;          // 반지름(단위: 미터)
    private final double surfaceGravity;  // 표면중력(단위: m / s^2)

    // 중력상수 (단위: m^3 / kg s^2)
    private static final double G = 6.67300E-11;

    // 생성자
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        this.surfaceGravity = G * mass / (radius * radius);
    }

    public double surfaceWeight(double mass) {
        return mass * surfaceGravity;
    }
}</code></pre>
<p>열거 타입 상수 각각을 특정 데이터와 연관지으려면 생성자에서 데이터를 받아 인스턴스 필드에 저장하면 된다.</p>
<h4 id="열거-타입은-근본적으로-불변이라-모든-필드는-final이어야-한다">열거 타입은 근본적으로 불변이라 모든 필드는 final이어야 한다.</h4>
<p>필드를 public으로 선언해도 되지만 private로 두어 별도의 public 접근자 메서드를 두는게 낫다.</p>
<p>어떤 객체의 지구에서의 무게를 입력받아 행성에서의 무게를 출력하는 일을 
다음같이 짧게 작성할 수도 있다.</p>
<pre><code class="language-java">public classs WeightTable {
    public static void main(String[] args) {
        double earthWeight = Double.parseDouble(args[0]);
        double mass = earthWeight / Planet.EARTH.surfaceGravity();
        for (Planet p : Palanet.values()) 
            System.out.println(&quot;%s에서 무게는 %f이다. %n&quot;, p, p.surfaceWeight(mass));
    }
}</code></pre>
<h3 id="지원하는-메서드">지원하는 메서드</h3>
<ul>
<li><code>values()</code> : 자신 안에 정의된 상수들의 값을 배열에 담아 반환하는 
정적 메서드, 값들은 선언된 순서로 저장</li>
<li><code>valueOf()</code> : 상수 이름을 입력받아 그 이름에 해당하는 상수를 반환</li>
<li><code>toString()</code> : 상수 이름을 문자열로 반환, 원하는 대로 재정의도 가능하다.</li>
<li><code>fromString()</code> : <code>toString</code>이 반환하는 문자열을 해당 열거 타입 상수로 변환</li>
</ul>
<h4 id="열거-타입에서-상수를-하나-제거하면">열거 타입에서 상수를 하나 제거하면?</h4>
<p>제거한 상수를 참조하지 않는 클라이언트에는 아무 영향이 없다.
제거된 상수를 참조하는 클라이언트는 컴파일타임에 오류가 발생해 이를 잡을 수 있다.</p>
<h3 id="상수마다-동작이-달라져야-할-경우">상수마다 동작이 달라져야 할 경우</h3>
<p>사칙연산 계산기의 연산 종류를 열거 타입으로 선언하고,
실제 연산까지 열거 타입 상수가 직접 수행하기로 한다.</p>
<pre><code class="language-java">public enum Operation {
    PLUS, MINUS, TIMES, DIVIDE
}</code></pre>
<h4 id="switch-문으로-분기처리"><code>switch</code> 문으로 분기처리</h4>
<pre><code class="language-java">/* 상수가 뜻하는 연산을 수행한다. */
public double apply(double x, double y) {
    switch(this) {
        case PLUS: return x + y;
        case MINUS: return x - y;
        case TIMES: return x * y;
        case DIVIDE: return x / y;
    }
    throw new AssertionError(&quot;알 수 없는 연산: &quot; + this);
}</code></pre>
<p>이 방법의 단점은 깨지기 쉬운 코드라는 것이다.
새로운 상수를 추가하면 해당 case 문도 추가해주어야 한다.</p>
<p>하지만 기존 열거 타입에 상수별 동작을 혼합해서 넣을 때는 좋은 선택이다.
추가하려는 메서드가 의미상 열거 타입에 속하지 않는다면 직접 만든 열거 타입이라도 이 방식이 유용하다.</p>
<h4 id="apply-추상-메서드-선언"><code>apply()</code> 추상 메서드 선언</h4>
<pre><code class="language-java">public enum Operation {
    PLUS {public double apply(double x, double y) {return x + y;}},
    MINUS {public double apply(double x, double y) {return x + y;}},
    TIMES {public double apply(double x, double y) {return x + y;}},
    DIVIDE {public double apply(double x, double y) {return x + y;}};

    public abstract double apply(double x, double y);
}</code></pre>
<p><code>apply()</code>가 추상 메서드이므로 재정의하지 않았다면 컴파일 오류로 알려준다.</p>
<h4 id="상수별-클래스-몸체와-데이터를-사용">상수별 클래스 몸체와 데이터를 사용</h4>
<pre><code class="language-java">public enum Operation {
    PLUS(&quot;+&quot;) {
        public double apply(double x, double y) {return x + y;}
    }
    MINUS(&quot;-&quot;) {
        public double apply(double x, double y) {return x - y;}
    }
    TIMES(&quot;*&quot;) {
        public double apply(double x, double y) {return x * y;}
    }
    DIVIDE(&quot;/&quot;) {
        public double apply(double x, double y) {return x / y;}
    };

    private final String symbol;

    Operation(String symbol) {this.symbol = symbol;}

    @Override public String toString() {return symbol;}
    public abstract double apply(double x, double y);
}</code></pre>
<h4 id="열거-타입용-fromstring-메서드-구현">열거 타입용 fromString 메서드 구현</h4>
<pre><code class="language-java">private static final Map&lt;String, Operation&gt; stringToEnum = 
Stream.of(values()).collect(toMap(Object::toString, e -&gt; e));

/* 지정한 문자열에 해당하는 Operation을 (존재한다면) 반환한다. */
public static Optional&lt;Operation&gt; fromString(String symbol) {
    return Optional.ofNullable(stringToEnum.get(symbol));
}
</code></pre>
<p>Operation 상수가 stringToEnum 맵에 추가되는 시점은 
열거 타입 상수 생성 후 정적 필드가 초기화 될 때이다.</p>
<p>위 예제는 values 메서드가 반환하는 배열 대신 스트림을 사용했다.</p>
<p>열거 타입 상수는 생성자에서 자신의 인스턴스를 맵에 추가할 수 없다.
이렇게 하려면 컴파일 오류가 나는데, 이 방식이 허용된다면 런타임에 <code>NullPointerException</code>이 발생했을 것이다.</p>
<p>열거 타입의 정적 필드 중 열거 타입의 생성자에서 접근할 수 있는 것은 상수 변수 뿐이다.</p>
<p>열거 타입 생성자가 실행되는 시점에는 정적 필드들이 아직 초기화되기 전이라, 
자기 자신을 추가하지 못하게 하는 제약이 꼭 필요하다.
특수한 예로, 열거 타입 생성자에서 같은 열거 타입의 다른 상수에도 접근할 수 없다. 
(열거 타입의 각 상수는 해당 열거 타입의 인스턴스를 <code>public static final</code> 필드로 선언했다.
즉, 다른 형제 상수도 <code>static</code>이므로 열거 타입 생성자에서 정적 필드에 접근할 수 없다는 제약이 적용된다.)</p>
<p>또한, 위 예제에서 <code>fromString</code>이 <code>Optional&lt;Operation&gt;</code>을 반환하는 점도 주의하자.
주어진 문자열이 가리키는 연산이 존재하지 않을 수 있음을 클라이언트에 알리고, 
그 상황을 클라이언트에서 대처하도록 한 것이다.</p>
<h4 id="값에-따라-분기하여-코드를-공유하는-열거-타입---좋은-방법인가">값에 따라 분기하여 코드를 공유하는 열거 타입 - 좋은 방법인가?</h4>
<p>상수별 메서드 구현에는 열거 타입 상수끼리 코드를 공유하기 어렵다는 단점이 있다.
예시로 급여명세서에서 쓸 요일을 표현하는 열거 타입을 예로 생각해 보면,
직원의 기본 임금, 그날 일한 시간이 주어지면 일당을 계산해주는 메서드를 가지고 있다.
주중에 오버타임이 발생하면 잔업 수장이 주어지고, 주말에는 무조건 잔업 수당이 주어진다.
<code>switch</code> 문을 이용하면 case 문을 날짜별로 두어 이 계산을 쉽게 수행할  수 있다. </p>
<pre><code class="language-java">enum PayrollDay {
    MONDAY, TUESDAY, WEDSDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;

    private static final int MINS_PER_SHIFT = 8 * 60;

    int pay(int minutesWorked, int payRate) {
        int basePay = minutesWorked * payRate;

        int overtimePay;
        switch(this) {
            case SATURDAY: case SUNDAY: // 주말
                overtimePay = basePay / 2;
                break;
            default: // 주중
                overtimePay = minutesWOrked &lt;= MINS_PER_SHIFT ?
                0 : minutesWorked - MINS_PER_SHIFT) * payRate / 2;
        }

        return basePay + overtimePay;
    }
}</code></pre>
<p>이 코드의 문제점은 휴가와 같은 새로운 값을 열거 타입에 추가하려면 그 값을 처리하는 
<code>case</code>문을 잊지 말고 쌍으로 넣어줘야 한다.</p>
<p>PayrollDay에 평일 잔업수당 계산용 메서드인 overtimePay를 구현해놓고,
주말 상수에서만 재정의해 써도, 새로운 상수를 추가하면서 overtimePay 메서드를 
재정의하지 않으면 평일용 코드를 그대로 물려받게 된다.</p>
<h4 id="정략-열거-타입-패턴">정략 열거 타입 패턴</h4>
<p>새로운 상수를 추가할 때 잔업수당 &#39;전략&#39;을 선택하도록 하는 것이다.
잔업 수당 계산을 private 중첩 열거 타입(PayType)으로 옮기고,
PayrollDay 열거 타입의 생성자에서 이 중 적당한 것을 선택한다.</p>
<p>그러면 payrollDay 열거 타입은 잔업수당 계산을 그 전략 열거 타입에 위임하여, 
switch 문이나 상수별 메서드 구현이 필요 없게 된다.</p>
<pre><code class="language-java">enum PayrollDay {
    MONDAY, TUESDAY, WEDSDAY, THURSDAY, FRIDAY, 
    SATURDAY(PayTyoe.WEEKEND), SUNDAY(PayType.WEEKEND);

    private final PayType payType;

    PayrollDya(PayType payTyoe) {this.payType = payType;}

    int pay(int minutesWorked, int payRate) {
        return payType.pay(minutesWorked, payRate);
    }

    /* 전략 열거 타입 */
    enum PayType {
        WEEKDAY {
            int overtimePay(int minusWorked, int payRate) {
                return minusWorked &lt;= MINS_PER_SHIFT ? 0 :
                (minusWorked - MINS_PER_SHIFT) * payRate / 2;
            }
        },
        WEEKEND {
            int overtimePay(int minusWorked, int payRate) {
                return minusWorked * payRate / 2;
            }
        };

        abstract int overtimePay(int mins, int payRate);
        private static final int MINS_PER_SHIFT = 8 * 60;

        int pay(int minsWorked, int payRate) {
            int basePay = minsWorked * payRate;
            return basePay + overtimePay(minsWorked, payRate);
        }
    }
}</code></pre>
<h3 id="필요한-원소를-컴파일타임에-다-알-수-있는-상수-집합이라면-항상-열거-타입을-사용하자">필요한 원소를 컴파일타임에 다 알 수 있는 상수 집합이라면, 항상 열거 타입을 사용하자</h3>
<p>열거 타입에 정의된 상수 개수가 영원히 고정 불변일 필요는 없다.
열거 타입은 나중에 상수가 추가돼도 바이너리 수준에서 호환되도록 설계되었다.</p>
<h3 id="정리">정리</h3>
<ul>
<li>열거 타입은 정수 상수보다 읽기 쉽고, 안전하고 강력하다.</li>
<li>열거 타입은 명시적 생성자나 메서드 없이 쓰이지만, 각 상수를 특정 데이터와 
연결짓거나 상수마다 다르게 동작하게 할 때 필요하다.</li>
<li>드물게 하나의 메서드가 상수별로 다르게 동작해야 할 때도 있다.
이런 열거 타입에서는 switch 문 대신 상수별 메서드 구현을 사용한다.</li>
<li>열거 타입 상수 일부가 같은 동작을 공유하면 전략 열거 타입 패턴을 사용하자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective java] item 28. 배열보다는 리스트를 사용하라]]></title>
            <link>https://velog.io/@new_wisdom/Effective-java-item-28.-%EB%B0%B0%EC%97%B4%EB%B3%B4%EB%8B%A4%EB%8A%94-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@new_wisdom/Effective-java-item-28.-%EB%B0%B0%EC%97%B4%EB%B3%B4%EB%8B%A4%EB%8A%94-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</guid>
            <pubDate>Wed, 17 Feb 2021 00:27:21 GMT</pubDate>
            <description><![CDATA[<p>우테코 Level 1 로또 미션에서 &quot;배열 대신 ArrayList를 사용한다.&quot;가 요구사항에 들어있었다.
왜 배열대신 ArrayList를 사용하라는 것일까?
찾아보니 이펙티브 자바에서도 그 내용이 나와 있어서 스스로의 물음에 답하는 내용을 정리하려 한다.</p>
<h2 id="array배열-vs-arraylist리스트">Array(배열) vs ArrayList(리스트)</h2>
<p>들어가기에 앞서 이펙티브 자바를 보기 전 Array과 ArrayList의 차이점을 간단히 적어본다.</p>
<h3 id="array배열">Array(배열)</h3>
<ul>
<li>사이즈가 정적인 데이터 구조이다. 일단 생성되면 크기를 변경할 수 없다.</li>
<li>원시 타입과 객체 모두 원소로 포함할 수 있다.</li>
<li><code>for</code> 또는 <code>for-each</code> 루프를 통해서 반복된다.</li>
<li>길이에 대해 <code>length</code> 변수를 사용한다.</li>
<li>Generic(제네릭)을 사용 할 수 없다.</li>
<li>원소를 할당하기 위해 할당 연산자<code>=</code>를 사용한다. </li>
</ul>
<h3 id="arraylist리스트">ArrayList(리스트)</h3>
<ul>
<li>사이즈가 동적인 데이터 구조이다. 용량을 초과하는 요소를 추가하면 크기가 자동으로 증가한다.</li>
<li>객체 원소만 포함할 수 있다.</li>
<li>요소를 반복하는 iterators를 제공한다.</li>
<li>길이에 대해 <code>size()</code> 메서드를 사용한다.</li>
<li>Generic(제네릭)을 지원한다.</li>
<li>원소를 할당하기 위해 <code>add()</code> 메서드를 사용한다.</li>
<li>Collections가 제공하는 다양한 메소드들을 사용할 수 있다.</li>
</ul>
<h1 id="effective-java-item-28">Effective Java item 28</h1>
<h2 id="배열과-제네릭-타입의-차이">배열과 제네릭 타입의 차이</h2>
<h3 id="배열은-공변이다">배열은 공변이다.</h3>
<p><code>Sub</code>가 <code>Super</code>의 하위 타입이라면 배열 <code>Sub[]</code>는 <code>Super[]</code>의 하위 타입이 된다.
즉 함께 변한다는 말이다.
하지만 제네릭은 불공변으로 서로 다른 타입 <code>Type1</code>, <code>Type2</code>가 있을 때, 
<code>List&lt;Type1&gt;</code>은 <code>List&lt;Type2&gt;</code>의 하위 타입도, 상위 타입도 아니다.</p>
<h4 id="공변이-왜-문제가-되지">공변이 왜 문제가 되지?</h4>
<p>아래 코드는 문법상 허용은 되지만 런타임에 실패한다.</p>
<pre><code class="language-java">Object[] objectArray = new Long[1];
/* ArrayStoreException 발생 */
objectArray[0] = &quot;타입이 달라 넣을 수 없음&quot;;</code></pre>
<p>또 아래 코드는 컴파일 오류를 일으킨다.</p>
<pre><code class="language-java">List&lt;Object&gt; objectList = new ArrayList&lt;Long&gt;();
objectList.add(&quot;타입이 달라 넣을 수 없음&quot;);</code></pre>
<p>두 코드 모두에서 Long용 저장소에 String을 넣을 수 없다.
배열은 이를 런타임에 알게 되지만 리스트는 컴파일 때 바로 알 수 있다.</p>
<h3 id="배열은-실체화된다">배열은 실체화된다.</h3>
<p>배열은 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다.
때문에 Long용 저장소에 String을 넣으려 하면 ArrayStoreException을 발생시킨다.</p>
<p>하지만 제네릭은 타입 정보가 런타임에는 소거된다.
이는 원소의 타입을 컴파일 타임에만 검사하며 런타임에는 알 수 없다는 것이다.
여기서 타입 정보의 소거라 함은 제네릭이 지원되기 전 
레거시 코드와 제네릭 타입을 함께 사용할 수 있게 해준다.</p>
<h2 id="제네릭-배열을-만들지-못하게-한-이유">제네릭 배열을 만들지 못하게 한 이유?</h2>
<p>그 이유는 타입 안전하지 않기 떄문이다.
제네릭 배열을 허용한다면 컴파일러가 자동 생성한 형변환 코드에서 런타임에 ClassCastException이
발생할 수 있는데, 이는 런타임에 이 예외가 발생하는 일을 막겠다는 제네릭 타입 시스템 취지에 벗어난다.</p>
<pre><code class="language-java">List&lt;String&gt;[] stringLists = new List&lt;String&gt;[1]; // (1) 
List&lt;Integer&gt; intList = List.of(42);              // (2)
Object[] objects = stringLists;                   // (3)
objects[0] = intList;                             // (4)
String s = stringLists[0].get(0);                 // (5)</code></pre>
<p>만약 (1)이 허용된다면 (2)는 원소가 하나인 <code>List&lt;Integer&gt;</code>를 생성한다. 
(3)은 (1)에서 생성한 <code>List&lt;String&gt;</code>의 배열을 <code>Object</code> 배열에 할당한다.
배열은 공변이니 아무 문제가 없다.
(4) 번은 (2)에서 생성한 <code>List&lt;Integer&gt;</code>의 인스턴스를 <code>Object</code> 배열의 첫 원소로 저장한다. 
제네릭은 런타임 시점에서 타입 정보를 소거하니 <code>List&lt;Integer&gt;</code>은 <code>List</code>가 되고 
<code>List&lt;Integer&gt;[]</code>는 <code>List[]</code>가 된다. 
따라서 (4)에서도 ArrayStoreException이 발생하지 않는다.
(5)에서는 <code>List&lt;String&gt;</code> 인스턴스만 담겠다고 선언한 <code>stringLists</code> 배열에는 
<code>List&lt;Integer&gt;</code> 인스턴스가 저장돼 있다.
(5)는 이 배열의 처음 리스트에서 첫 원소를 꺼내려 하는데 컴파일러는 꺼낸 원소를 자동으로 String으로
형변환 하는데, 이 원소는 <code>Integer</code>이니 런타임에 ClassCastExceptiondl qkftodgksek.</p>
<p>이를 막기 위해서 제네릭 배열 생성을 막도록 (1)에서 컴파일 오류를 내야 한다.</p>
<h2 id="실체화-불가-타입">실체화 불가 타입</h2>
<p><code>E</code>, <code>List&lt;E&gt;</code>, <code>List&lt;String&gt;</code> 같은 타입을 실체화 불가 타입이라 한다. 
제네릭은 타입 소거로 인해 실체화되지 않아서 런타임에는 컴파일타임보다 타입 정보를 적게 가지는 타입을 뜻한다.
(매개변수화 타입 가운데 실체화 될 수 있는 타입은 비한정적 와일드카드 타입 뿐이다.)</p>
<h2 id="정리">정리</h2>
<p>배열과 제네릭에는 매우 다른 타입 규칙이 적용되어서 둘을 섞어 쓰기란 쉽지 않다.
배열은 공변, 제네릭은 불공변이다. 
이 말은 배열은 런타임 타입에 안전하지만 컴파일 타임에 안전하지 못하다.
제네릭은 그 반대이다.</p>
<p>단순히 사이즈가 정적인지 동적인지의 차이 뿐만 아니라 배열과 리스트에는 이렇게 많은
차이점이 존재하고 있었다.</p>
<p>만약 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 먼저 배열을 리스트로 대처하자!</p>
<h2 id="참고-자료">참고 자료</h2>
<ul>
<li><a href="https://www.quora.com/What-is-the-difference-between-an-array-and-an-array-list#:~:targetText=First%20and%20Major%20difference%20between%20Array%20and%20ArrayList%20in%20Java,primitives%20and%20Objects%20in%20Java.">What is the difference between an array and an array list?
</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 불변 객체 (Immutable Class)]]></title>
            <link>https://velog.io/@new_wisdom/Java-%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4-Immutable-Class</link>
            <guid>https://velog.io/@new_wisdom/Java-%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4-Immutable-Class</guid>
            <pubDate>Mon, 15 Feb 2021 09:49:32 GMT</pubDate>
            <description><![CDATA[<h2 id="불변-객체-immutable-class란">불변 객체 (Immutable Class)란?</h2>
<p>불변 객체란 말 그대로 <strong>변경이 불가능한 객체</strong>이다.
객체를 생성 후 외부에 의해 그 상태를 바꿀 수 없다.
여기서 바꿀 수 없다는 것은 heap 영역에서 그 객체가 가리키고 있는 
데이터 자체의 변화가 불가능 함을 의미하며 stack에 있는 주소값을 다른 주소값을 
가리키도록 변경하는 것은 문제 없다.</p>
<h4 id="➕-여기서-말하는-heap-영역이란-무엇인가">➕ 여기서 말하는 heap 영역이란 무엇인가?</h4>
<p><img src="https://images.velog.io/images/new_wisdom/post/100109a2-befa-450c-921b-caf06e70cfd1/image.png" alt="">
간단하게 말해 원시타입(int, boolean 등)은 그대로 stack 영역에 올라가지만,
참조변수를 가지고 있는 타입(Object, Array 등)은 그 실제 데이터들은 heap 영역에 저장하고 이 주소값을 Stack 영역에 가지고 있다.</p>
<p>예시로 <code>String name = &quot;amazzi&quot;;</code>에서 <code>name = &quot;newwisdom&quot;;</code>으로 
name이 가리키는 주소의 변경은 가능하다. 
여기서 String은 불변 객체로 name의 값을 바꿔준 것처럼 보이지만 실제로는 
String 객체에 <code>&quot;newwisdom&quot;</code>을 인스턴스 변수로 가지고 있는 새로운 객체를 참조하고 있는 것이다.
즉 name이 처음에 참조하는 값이 변경되는게 아닌 아예 새로운 객체를 만들고 
이를 name이 참조하고 있는 것이다.</p>
<h2 id="불변-객체의-특징">불변 객체의 특징</h2>
<h3 id="장점">장점</h3>
<ul>
<li>생성자, 접근 메소드에 대한 방어적 복사가 필요없다.</li>
<li>멀티 스레드 환경이라면 동기화 처리 없이 객체를 공유할 수 있다. </li>
<li>불변이기 때문에 객체를 신뢰할 수 있다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>객체가 가지는 값마다 새로운 인스턴스를 생성해야한다. </li>
</ul>
<p>근데 수업시간에서 제이슨이 말하기를 Oracle 공식 문서에는 
&quot;불변 객체는 여러분이 메모리를 걱정하는 것보다 훨씬 큰 이익을 가져옵니다.&quot;
이런 뉘앙스의 문장이 있다고 한다.</p>
<h2 id="여러-타입에서의-불변">여러 타입에서의 불변</h2>
<h3 id="원시-타입만-있는-경우에서-불변">원시 타입만 있는 경우에서 불변</h3>
<p>원시 타입에서의 불변은 쉽다. 
원시 타입은 참조 값이 없기 때문에 값을 그대로 외부에 내보내도 내부 객체는 불변이다.</p>
<h4 id="example">Example</h4>
<pre><code class="language-java">class Person {
    private final int age;
    private final int name;

    public Person(int age, int name) {
        this.age = age;
        this.name = name;
    }
}</code></pre>
<p>인스턴스 변수들이 <code>final</code>로 선언되었기 때문에 인스턴스 값의 변경이 불가능하다.
따라서 setter 메소드도 사용이 불가능하다. </p>
<p>이 객체의 인스턴스 변수들의 값을 변경하려면 새로운 인스턴스를 만드는 방법 뿐이다.</p>
<h2 id="참조-타입이-있는-경우에서-불변">참조 타입이 있는 경우에서 불변</h2>
<p>&quot;원시 타입만 있는 경우 처럼 단순히 <code>final</code>을 붙이고 setter 메소드만 안사용하면 되지 않아?&quot;라는 
질문에 대한 대답은 아래와 같은 예시를 보면 된다.</p>
<pre><code class="language-java">public class Car {

    private final Position position;

    public Car(final Position position) {
        this.position = position;
    }

    public Position getPosition() {
        return position;
    }
}</code></pre>
<pre><code class="language-java">public class Position {

    private int value;

    public Position(final int value) {
        this.value = value;
    }

    public void setValue(final int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}</code></pre>
<p>여기서 Car는 불변 객체인가?
아니다. 
Car는 final을 사용하고, setter가 없지만 우리는 Car의 position을 변경할 수 있다.</p>
<pre><code class="language-java">public static void main(String[] args) {
    Position position = new Position(1);
    Car car = new Car(position);

    System.out.println(car.getPosition().getValue());
    // 1

    car.getPosition().setValue(10);
    System.out.println(car.getPosition().getValue());
    // 10
}</code></pre>
<p>불변 객체라고 생각했던 Car 내부의 참조변수 Position은 불변 객체가 아니었기 때문에
Car 또한 불변 객체가 될 수 없었다.
즉, 불변 객체의 참조 변수 또한 불변, 불변 객체여야 한다.</p>
<h3 id="참조-변수가-일반-객체인-경우">참조 변수가 일반 객체인 경우</h3>
<p>위 예제에서 참조 변수인 Position도 불변 객체로 만든다.</p>
<pre><code class="language-java">public class Car {

    private final Position position;

    public Car(final Position position) {
        this.position = position;
    }

    public Position getPosition() {
        return position;
    }
}</code></pre>
<pre><code class="language-java">public class Position {

    private final int value;

    public Position(final int value) {
        this.value = value;
    }

    public void setValue(final int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}</code></pre>
<h3 id="참조-변수가-list일-경우">참조 변수가 List일 경우</h3>
<p>참조변수가 List일 경우는 List에 담고 있는 객체가 불변 객체여도 주의해야한다.
이 경우는 다음과 같은 조건을 만족 시켜야 한다.</p>
<h4 id="생성-시-생성-인자를-그대로-참조하지-않아야-한다-new-arraylist">생성 시 생성 인자를 그대로 참조하지 않아야 한다. (new ArrayList&lt;&gt;())</h4>
<p>생성될 때 인자로 넘어온 List를 외부에서 변경하면 List를 가진 객체의 내부 인스턴스 또한 변한다.
때문에 생성자를 통해 값을 전달 받을 때 <code>new ArrayList&lt;&gt;()</code>를 통해 
새로운 값을 참조하도록 방어적 복사를 도입해야 한다.
이러면 외부에서 넘겨주는 List와 객체 내부의 인스턴스 변수가 참조하는 값이 
다르기 때문에 외부에서 제어가 불가능하다.</p>
<h4 id="getter를-통해-addremove가-불가능하도록-collectiionsunmodifiablelist-메소드를-사용">getter를 통해 add/remove가 불가능하도록 Collectiions.unmodifiableList() 메소드를 사용</h4>
<p>getter를 통해 List의 참조변수를 그대로 내보내게 되면 
<code>Collections</code>의 API를 통해 이 값을 추가/삭제할 수 있다. 
때문에 getter 메소드 구현 시 이를 통해 add/remove가 불가능하도록 
List의 값 변경을 막는 <code>Collectiions.unmodifiableList()</code> 메소드를 사용해야 한다. </p>
<pre><code class="language-java">public class Positions {

    private final List&lt;Position&gt; positions;

    public Positions(final List&lt;Position&gt; positions) {
        this.positions = new ArrayList&lt;&gt;(positions);
    }

    public Position getPosition() {
        return Collections.unmodifiableList(position);
    }
}</code></pre>
<h2 id="참고-자료">참고 자료</h2>
<ul>
<li><a href="https://limkydev.tistory.com/68">[Java] Immutable Class (불변 클래스)</a></li>
<li><a href="https://woowacourse.github.io/javable/post/2020-05-18-immutable-object/">불변객체를 만드는 방법</a></li>
<li><a href="https://velog.io/@conatuseus/Java-Immutable-Object%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4">[Java] Immutable Object(불변객체)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] String vs StringBuffer vs StringBuilder]]></title>
            <link>https://velog.io/@new_wisdom/Java-String-vs-StringBuffer-vs-StringBuilder</link>
            <guid>https://velog.io/@new_wisdom/Java-String-vs-StringBuffer-vs-StringBuilder</guid>
            <pubDate>Mon, 15 Feb 2021 07:18:24 GMT</pubDate>
            <description><![CDATA[<p>자바의 불변 객체를 공부하다가 String 과 StringBuilder가 예시로 자주 등장함을 보게 되었다.
나도 Java를 제대로 공부한지 얼마 안되서,
사실 String, StringBuffer, StringBuilder의 명확한 차이를 잘모르고
그냥 가져다 썼는데, 자바의 정석을 읽어보니 이 String이 굉장히 흥미로워서 👀
이번 기회에 명확히 정리하고 가는 것이 좋다고 생각했다.</p>
<h2 id="string">String</h2>
<p>String은 참 특이한 존재이다.
다른 언어에서 문자열이란 대부분 char형의 배열로 다루는데,
자바에서는 이 문자열을 위한 클래스가 존재한다는 것이다.</p>
<p>이 String 클래스를 깊게 보기 위해 String 클래스가 어떻게 이루어져 있는지 들여다보자.
<strong>String.java 일부</strong></p>
<pre><code class="language-java">public final class String
    implements java.io.Serializable, Comparable&lt;String&gt;, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    ...

    public String() {
        this.value = &quot;&quot;.value;
    }

    /**
     * Initializes a newly created {@code String} object so that it represents
     * the same sequence of characters as the argument; in other words, the
     * newly created string is a copy of the argument string. Unless an
     * explicit copy of {@code original} is needed, use of this constructor is
     * unnecessary since Strings are immutable.
     *
     * @param  original
     *         A {@code String}
     */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    /**
     * Allocates a new {@code String} so that it represents the sequence of
     * characters currently contained in the character array argument. The
     * contents of the character array are copied; subsequent modification of
     * the character array does not affect the newly created string.
     *
     * @param  value
     *         The initial value of the string
     */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }
</code></pre>
<p>String 클래스는 인스턴스 변수로 몇 가지를 가지고 있는데
그 중 문자열을 저장하기 위해 문자형 배열 변수 <code>char[] value</code>가 있다.
또 생성자를 보면 인스턴스 생성 시 생성자의 매개변수로 입력 받는 문자열이 
이 인스턴스 변수에 문자형 배열로 저장되는 것을 확인할 수 있다. 
또한 <code>final</code> 키워드로 변경이 불가능한 <strong>불변 객체</strong>임을 확인할 수 있다.</p>
<p>또 생성된 String 인스턴스가 가지고 있는 문자열은 읽을 수만 있고, 변경할 수는 없다.(불변 객체)</p>
<p>만약 연산자를 통해 문자열을 결합하는 경우는 String 인스턴스 내의 value 값이 변하는게 아닌,
새로운 문자열이 담긴 String 인스턴스를 반환한다.
때문에 문자열을 결합할 때마다 새로운 문자열을 가진 String 인스턴스를 생성하는 것이다.
이는 무분별한 메모리 공간 차지의 문제를 일으킬 수 있다.</p>
<h3 id="string의-비교">String의 비교</h3>
<p>문자열을 만들 때 문자열 리터럴을 지정하는 방법과 String 클래스의 생성자를 이용해 만드는 법이 있다.</p>
<pre><code class="language-java">/*문자열 리터럴*/
String str1 = &quot;amazzi&quot;;
String str2 = &quot;amazzi&quot;;

/*String 클래스의 생성자*/
String str3 = new String(&quot;amazzi&quot;);
String str4 = new String(&quot;amazzi);</code></pre>
<h4 id="string-클래스-생성자">String 클래스 생성자</h4>
<p>String 클래스 생성자는 new 연산자에 의해 새로운 메모리가 할당된다.
즉 항상 새로운 String 인스턴스가 생성되며 각각의 주소값을 갖는다.</p>
<h4 id="문자열-리터럴">문자열 리터럴</h4>
<p>문자열 리터럴은 클래스가 메모리에 로드될 때 자동적으로 생성되어 이미 존재하는 것을 재사용한다.
때문에 같은 내용의 문자열 리터럴은 한번만 저장되며 
같은 문자열은 하나의 인스턴스를 공유하고 참조변수만이 다를 뿐이다.</p>
<p>그렇다면 문자열 리터럴로 만든 str1, str2와 
String 클래스의 생성자로 만든 str3, str4 각각의 비교 결과는 어떠할까?</p>
<pre><code class="language-java">str1.equals(str2); // true
str3.equals(str4); // true

str1 == str2; // true
str3 == str4 // false</code></pre>
<p><code>equals()</code> 사용을 통한 비교에서는 두 문자열의 내용을 비교하기 때문에 두 비교 결과 모두 true이다.
하지만 등가비교연산자 <code>==</code>를 통해 주소를 비교했을 경우,
str3, str4는 각각 다른 주소값을 가지고 있기 때문에 false가 나온다.</p>
<h2 id="stringbuffer">StringBuffer</h2>
<p>String 클래스는 불변 클래스이기 때문에 문자열을 변경할 수 없었으나,
StringBuffer는 변경이 가능하다.
StringBuffer는 할당된 값을 변경하더라도, 
String 클래스처럼 새로운 객체를 만들지 않고 기존 할당된 값을 수정하는 것으로 처리한다.
내부적으로 문자열 편집을 위한 버퍼를 가지고 있으며 StringBuffer 인스턴스를 생성할 때 
그 크기를 지정할 수 있다. </p>
<p>마찬가지로 StringBuffer 클래스를 들여다보자.
<strong>StringBuffer.java 일부</strong></p>
<pre><code class="language-java">public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    static final long serialVersionUID = 3388685877147921107L;

    /**
     * Constructs a string buffer with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuffer() {
        super(16);
    }

    /**
     * Constructs a string buffer with no characters in it and
     * the specified initial capacity.
     *
     * @param      capacity  the initial capacity.
     * @exception  NegativeArraySizeException  if the {@code capacity}
     *               argument is less than {@code 0}.
     */
    public StringBuffer(int capacity) {
        super(capacity);
    }

    /**
     * Constructs a string buffer initialized to the contents of the
     * specified string. The initial capacity of the string buffer is
     * {@code 16} plus the length of the string argument.
     *
     * @param   str   the initial contents of the buffer.
     */
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

    /**
     * Constructs a string buffer that contains the same characters
     * as the specified {@code CharSequence}. The initial capacity of
     * the string buffer is {@code 16} plus the length of the
     * {@code CharSequence} argument.
     * &lt;p&gt;
     * If the length of the specified {@code CharSequence} is
     * less than or equal to zero, then an empty buffer of capacity
     * {@code 16} is returned.
     *
     * @param      seq   the sequence to copy.
     * @since 1.5
     */
    public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }</code></pre>
<p>문자열을 저장하기 위한 <code>toStringCache</code> 변수가 보인다.
String 클래스와 차이점은 이 변수는 final로 선언되어 있지 않다는 것이다.
인스턴스를 생성할 때는 <code>StringBuffer(int capacity)</code> 생성자를 통해 길이를 지정해 줄 수 있으나,
지정해주지 않는다면 16개 문자를 저장할 수 있는 크기의 버퍼를 생성한다. 
만약 버퍼의 크기가 작업하려는 문자열의 길이보다 작을 때는 내부적으로 버퍼의 크기를 증가시키는 작업이 수행된다. </p>
<h3 id="stringbuffer의-변경">StringBuffer의 변경</h3>
<p>String 클래스와는 달리 append() 메소드로 값을 변경, 추가할 수 있다.
append()는 반환 값이 StringBuffer이며 자신의 주소를 반환한다. 
때문에 아래 코드는 sb에 새로운 문자열이 추가되고 sb 자신의 주소를 반환해 sb2에다
sb의 주소가 들어간다.</p>
<pre><code class="language-java">StringBuffer sb2 = sb.append(&quot;zzi&quot;);
</code></pre>
<h3 id="stringbuffer의-비교">StringBuffer의 비교</h3>
<p>String 클래스에서는 equals 메서드를 오버라이딩 하고 있어서 내용 비교가 가능했으나,
StringBuffer는 그렇지 않다. 때문에 <code>==</code>로 비교한 것과 같은 결과를 얻는다.</p>
<pre><code class="language-java">StringBuffer sb = new StringBuffer(&quot;abc&quot;);
StringVuffer sb2 = new StringVuffer(&quot;abc&quot;);
...
sb == sb2; // false
sb.equals(sb2); // false</code></pre>
<p>하지만 <code>toString()</code>을 오버라이딩하고 있기 때문에 이를 이용해 인스턴스를 얻고 <code>equals()</code>를 통해 비교할 수 있다.</p>
<pre><code class="language-java">String s = sb.toString();
String s2 = sb2.toString();
...
s.equals(s2); // true</code></pre>
<h2 id="stringbuilder">StringBuilder</h2>
<p>StringBuffer는 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전하다. (thread-safe)</p>
<p>반대로 StringBuilder는 동기화를 지원하지 않기때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer 보다 뛰어나다.</p>
<p>StringBuffer에서 스레드의 동기화만 뺀 것이 StringBuilder이고
둘의 기능은 완전이 동일하다.</p>
<p>(참고로 String도 불변성을 가지기때문에 마찬가지로 멀티쓰레드 환경에서의 안정성(thread-safe)을 가지고 있다.)</p>
<h2 id="정리">정리</h2>
<p>String :  문자열 연산이 적고 멀티쓰레드 환경일 경우
StringBuffer :  문자열 연산이 많고 멀티쓰레드 환경일 경우
StringBuilder :  문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우  </p>
<h3 id="참고-자료">참고 자료</h3>
<p><a href="https://ifuwanna.tistory.com/221">[Java] String, StringBuffer, StringBuilder 차이 및 장단점</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🪐 Woowa Course 🪐 ]]></title>
            <link>https://velog.io/@new_wisdom/Woowa-Course</link>
            <guid>https://velog.io/@new_wisdom/Woowa-Course</guid>
            <pubDate>Mon, 15 Feb 2021 05:13:53 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[[코드 리뷰 정리]  Level 1. 자동차 경주 게임]]></title>
            <link>https://velog.io/@new_wisdom/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%85%8C%ED%81%AC%EC%BD%94%EC%8A%A4-Level-1-%EC%9E%90%EB%8F%99%EC%B0%A8-%EA%B2%BD%EC%A3%BC-%EA%B2%8C%EC%9E%84-1%EB%8B%A8%EA%B3%84-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@new_wisdom/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%85%8C%ED%81%AC%EC%BD%94%EC%8A%A4-Level-1-%EC%9E%90%EB%8F%99%EC%B0%A8-%EA%B2%BD%EC%A3%BC-%EA%B2%8C%EC%9E%84-1%EB%8B%A8%EA%B3%84-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 15 Feb 2021 05:04:07 GMT</pubDate>
            <description><![CDATA[<p>우테코 레벨 1 난생 처음으로 코드리뷰를 받게 되었다.
사실 TDD도 처음이고, 누군가 내 코드를 읽고 피드백 받는 것 또한 처음인데
이런 기회가 정말 감사하면서도 떨렸던 첫 리뷰 요청이었다 👀</p>
<p>코드 리뷰를 받으니 내가 모르는 부분과 나의 실수들을 명확히 볼 수 있었다.
또한 리뷰를 보니 나의 잘못된 코딩 습관도 발견할 수 있었다.
덕분에 고민하고 공부해봐야 할 것들을 알 수 있어 
정말로 나에게 너무나도 큰 도움이 되었다 🙇‍♂️</p>
<p>피드백 받은 부분에서 계속 머릿 속에 박기 위해 
몇 가지는 정리하고 넘어가는 것이 좋을 것이라 판단이 되었다.</p>
<h3 id="불필요한-객체-생성을-피하라">불필요한 객체 생성을 피하라</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/919e1443-08eb-4fa8-9afb-64bad0266411/image.png" alt=""></p>
<h4 id="pattern-객체는-비싸다">Pattern 객체는 비싸다</h4>
<p>나는 지금껏 올바른 숫자인지, 문자인지 등을 검증할 때 
대부분 Pattern 객체를 정말 아무렇지 않게 사용했었다.</p>
<p>그리고 이를 쓰는 방법은 저렇게 메서드를 호출 시 패턴 객체를 매번 생성했다.</p>
<p>하지만 이번에 전반적인 리뷰들을 보니 정규식을 활용해 값을 검증한 로직에는
&quot;<code>Pattern</code>은 매우 비싼 객체이다.&quot; 라는 리뷰가 꼭 있었다.
부끄럽지만 프로그램을 구현하면서 성능까지 고려하지는 못했던 것 같다.</p>
<p><code>이펙티브 자바 item 6 불필요한 객체 생성을 피하라</code>와
<a href="https://goodgid.github.io/Regex-Performance-Caution/">이 글은 페어의 리뷰에 달린 글</a>을 나의 참고자료로 삼았다.</p>
<p>Pattern 인스턴스는 1번 사용되고 버려져서 
곧바로 GC의 대상이 되어 비싼 비용이 든다.</p>
<p>이런 Pattern 객체는 한 번 생성하고 재활용 할 수 있었고
아래와 같이 메소드 호출 시 매번 생성하는 효율성 떨어지는 방법을 버리고,
<code>static</code> 변수로 선언해주었다.</p>
<pre><code class="language-java">public class StringCalculator {
    private static final Pattern PATTERN = Pattern.compile(&quot;//(.)\n(.*)&quot;);</code></pre>
<h4 id="static을-사용하는-이유-명심하기">static을 사용하는 이유 명심하기</h4>
<p><img src="https://images.velog.io/images/new_wisdom/post/ab8f6793-f4dc-4afe-852e-626ab53b9474/image.png" alt="">
분명히 <a href="https://velog.io/@new_wisdom/Java-%EB%A9%94%EC%86%8C%EB%93%9C%EC%99%80-%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84#static-%EC%84%A0%EC%96%B8%EC%9D%84-%EB%B6%99%EC%97%AC%EC%84%9C-%EC%84%A0%EC%96%B8%ED%95%98%EB%8A%94-%ED%81%B4%EB%9E%98%EC%8A%A4">static을 사용하는 이유</a>에 대해서 자바 기본 개념에 정리했었는데 
구현 중 무분별하게 <code>static</code> 변수와 메소드를 사용하였다. 
static 을 사용할 때 &quot;변수가 선언된 클래스의 모든 인스턴스가 공유하는 변수인가?&quot;를 질문하지 않았고,
&quot;어떠한 인스턴스에도 속하지 않는 상태로 메모리 공간에 딱 하나만 존재함&quot;을 염두해두지 않은 문제였다.</p>
<p>&quot;<code>Cars</code>의 <code>List&lt;Car&gt; cars</code>는 프로그램이 실행되고 바로 메모리에 저장되어 
모든 인스턴스가 공유하는 값이어야하는가?&quot;를 질문하면 
저 코드를 뜯어 고쳐야 한다는 것을 단번에 알 수 있다.</p>
<p>또한 피드백을 받고 보니 일급 컬렉션을 본 의도대로 구현하지 못한 것 같아 
주신 <a href="https://velog.io/@new_wisdom/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EB%A8%B8%EB%A6%AC%EC%97%90-%EB%B0%95%EC%A0%9C%ED%95%A0%EB%9D%BC%EA%B3%A0-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%A0%95%EB%A6%AC%ED%95%9C-%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98feat.-jojoldu%EB%8B%98%EC%9D%98-%EB%AA%85%EA%B8%80">jojoldu님의 일급 컬렉션 글을 다시 정독</a>해보았다.</p>
<p>언급한 부분은 일급 컬렉션의 개념을 도입하고, 추가적으로 <a href="https://velog.io/@new_wisdom/Effective-java-item-1.-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%8C%80%EC%8B%A0-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%EA%B3%A0%EB%A0%A4%ED%95%98%EB%9D%BC">정적 팩터리 메서드를 공부하면서</a>
아래와 같이 대대적인 리팩토링을 거쳤다.</p>
<pre><code class="language-java">public class Cars {
    private final List&lt;Car&gt; cars;

    private Cars(final List&lt;Car&gt; cars) {
        this.cars = new ArrayList&lt;&gt;(cars);
    }

    public static Cars makeFromCarNames(final List&lt;Name&gt; carNames) {
        List&lt;Car&gt; cars = carNames.stream()
                .map(Car::new)
                .collect(Collectors.toList());
        validateNonDuplicatedNames(cars);
        return new Cars(cars);
    }</code></pre>
<p><img src="https://images.velog.io/images/new_wisdom/post/27bab82b-7355-4740-a0e1-3ae4ec9adf19/image.png" alt=""></p>
<p>내가 &quot;static을 사용하는 이유 명심하기&quot;를 &quot;불필요한 객체 생성을 피하라&quot;의 하위에 넣은 이유는 static 메서드나, static 상수만 갖고 있는 클래스는 굳이 새로 인스턴스로 생성할 필요가 없다.
즉<code>static</code>은 상태 값을 가지지 않아 인스턴스를 생성할 필요가 없다.
때문에 생성자를 <code>private</code> 접근자로 막아 불필요한 객체가 생성되는 것을 막아야 한다.</p>
<p>➕
리뷰어님께서 추가적으로 <a href="https://woowacourse.github.io/javable/post/2020-07-16-static-method/">static</a>과 <a href="https://woowacourse.github.io/javable/post/2020-05-08-First-Class-Collection/">일급 컬렉션</a>에 참고할만한 너무나도 유익한 글을 주셨다.
(추가로 깨달은 것을 짤막하게 남기자면 
<code>static</code>은 다형성을 위반하니 객체지향에서도 멀어지게 된다)
리뷰어님의 모든 코멘트가 내게 피가되고 살이된다 😭🙇‍♂️</p>
<h3 id="optional의-올바른-사용">Optional의 올바른 사용</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/17b671f6-81ff-4efd-a668-f1efeb46d086/image.png" alt=""></p>
<p><a href="http://homoefficio.github.io/2019/10/03/Java-Optional-%EB%B0%94%EB%A5%B4%EA%B2%8C-%EC%93%B0%EA%B8%B0/">주신 글</a>을 읽어보고 반환값이 ‘없음’을 나타내는 것이 주목적인 
Optional의 의도에 맞지 않은 <code>get()</code> 메소드를 사용한 문제점을 발견했다.
<a href="https://velog.io/@new_wisdom/Java-Optional-%ED%81%B4%EB%9E%98%EC%8A%A4">스스로도 Optional에 대해 정리</a> 했었는데 그냥 단순히 개념을 정리하기에 급급했나 싶기도 했다.</p>
<p>말씀해주신 대로 Car에 <code>Comparable</code> 인터페이스를 구현하여 
compareTo()를 오버라이드 하여 <code>map()</code>에서 최댓값을 구할 수 있도록 하였다.</p>
<pre><code class="language-java">public class Car implements Comparable&lt;Car&gt; {
    private static final String REGEX_ALPHA = &quot;^[a-zA-z]*$&quot;;
    private static final String REGEX_KOREAN = &quot;[가-힣]*$&quot;;
    private static final int NAME_LENGTH_LIMIT = 5;
    private static final int MOVE_PIVOT = 4;

    private String name;
    private int position;

    public Car(final String name) {
        validateName(name);
        this.name = name;
    }

    @Override
    public int compareTo(final Car anotherCar) {
        return Integer.compare(this.getPosition(), anotherCar.getPosition());
    }</code></pre>
<h4 id="수정한-메소드">수정한 메소드</h4>
<pre><code class="language-java">public Car getMaxPositionCar() {
        return cars.stream()
                .max(Car::compareTo)
                .orElseThrow(IllegalStateException::new);
    }</code></pre>
<h3 id="객체지향에서-get을-지양하자">객체지향에서 get을 지양하자</h3>
<p>이 부분은 리뷰어님과 DM으로 나눈 이야기에서 명확히 깨닫게 된 부분인데, 
get 메소드를 사용하는 순간 객체가 어떤 상태를 가지고 있는지 외부에 여실히 드러나게 된다.
데이터가 <code>private</code> 이어도 <code>public</code> get을 사용하면 외부에 알려지는 것이 된다.
위 피드백 코드에서도 <code>getPosition()</code>이 <code>position</code>이라는 데이터를 가지고 있음이 드러나니 자동차의 상태가 <code>maxPosition</code> 인지를 <code>car</code> 객체에서 확인하도록 하였다.</p>
<pre><code class="language-java">public boolean isMaxPosition(final Car maxPositionCar) {
        return this.position == maxPositionCar.getPosition();
}</code></pre>
<p>또 데일리 미팅 동기들과 이야기를 하다 깨닫게 된 것은 
나는 지금 tryCount라는 객체에서 값을 꺼내 <code>for</code> 문을 돌렸는데,
이는 <code>while</code>을 사용하여 tryCount에서 그 상태를 판별하도록 변경하였다.
<strong>수정 전</strong></p>
<pre><code class="language-java">private void raceByTryCount() {
    for (int i = 0; i &lt; tryCount.getCount(); i++) {
        race();
        RacingCarView.printProgressResult(cars.cars());
    }
}</code></pre>
<p><strong>수정 후</strong></p>
<pre><code class="language-java">private void raceByTryCount() {
    while (tryCount.isRemainCount()) {
        cars.race();
        RacingCarView.printProgressResult(cars.cars());
        tryCount.deductCount();
    }
}</code></pre>
<h3 id="hashset으로-wrapper-class-중복-제거">HashSet으로 Wrapper class 중복 제거</h3>
<p><img src="https://images.velog.io/images/new_wisdom/post/9df18814-3aeb-4d1d-8abb-7e5614dc42c8/image.png" alt="">
<code>Car</code> 클래스에 equals와 hashCode를 이미 Override 해놓았는데 
웃기게도 Name을 꺼내와서 HashSet으로 중복을 제거했다. 
(말그대로 이름의 중복 제거를 한거다 ㅎ)
HashSet은 내부적으로 먼저 해당 객체의 hashCode()와 equals()를 실행해본다.
관련 내용은 내가 <a href="https://velog.io/@new_wisdom/Java-equals%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90%EC%9D%98-%EB%B9%84%EA%B5%90">이전에 썼던 글이 있길래 그 부분에 추가적</a>으로 더 작성했다.</p>
<h3 id="이번-피드백으로-느낀-점">이번 피드백으로 느낀 점</h3>
<ul>
<li>프로그램의 성능을 고려하는 개발자가 되자</li>
<li>어떤 개념을 사용할 때 그 의미와 목적을 다시 한번 되새기자</li>
<li>레퍼런스를 찾아 글을 읽을 때 내가 얻고자 하는 해결 방법만 뚝딱 가져가는게 아닌,
그 내용을 완벽히 체화하자</li>
<li>이 전에 적은 공부 글들을 다시 보면서 그 부족함을 채워나가는 것도 좋은 방법인 것 같다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective java] item 1. 생성자 대신 정적 팩터리 메서드를 고려하라]]></title>
            <link>https://velog.io/@new_wisdom/Effective-java-item-1.-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%8C%80%EC%8B%A0-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%EA%B3%A0%EB%A0%A4%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@new_wisdom/Effective-java-item-1.-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%8C%80%EC%8B%A0-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%EA%B3%A0%EB%A0%A4%ED%95%98%EB%9D%BC</guid>
            <pubDate>Sun, 14 Feb 2021 13:34:01 GMT</pubDate>
            <description><![CDATA[<p>클래스는 생성자와 별도로 정적 팩터리 메서드(static factory method)를 제공할 수 있다. 디자인 패턴의 <code>팩터리 메서드</code>와는 다르다.</p>
<h2 id="장점">장점</h2>
<h3 id="1-이름을-가질-수-있다">1. 이름을 가질 수 있다.</h3>
<p>생성자에 넘기는 매개변수와 생성자만으로는 반환될 객체의 특성을 제대로 설명하지 못한다.
하지만 정적 팩터리 메서드는 반한될 객체의 특성을 메소드명을 통해 드러낼 수 있다. </p>
<ul>
<li>Exmaple - 생성자<pre><code class="language-java">public Cars(List&lt;String&gt; names) {
  validateNonDuplicatedNames(names);
  for (String name : names) {
      cars.add(new Car(name));
  }
}
private void validateNonDuplicatedNames(final List&lt;String&gt; names) {
  if (new HashSet&lt;&gt;(names).size() != names.size()) {
      throw new IllegalArgumentException(&quot;중복된 자동차 이름입니다.&quot;);
   }
}</code></pre>
</li>
<li>Example -정적 팩터리 메서드<pre><code class="language-java">  public static Cars makeFromCarNames(final List&lt;Name&gt; carNames) {
      List&lt;Car&gt; cars = carNames.stream()
              .map(Car::new)
              .collect(Collectors.toList());
      return new Cars(cars);
  }</code></pre>
자동차의 이름들로 자동차 객체를 생성하는 행동을 더 명확히 드러낸다.</li>
</ul>
<h3 id="2-호출될-때마다-인스턴스를-새로-생성하지-않아도-된다">2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.</h3>
<p>이 덕분에 불변 클래스는 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 
재활용하는 식으로 불필요한 객체 생성을 피할 수 있다. </p>
<ul>
<li>Example - <code>Boolean.valueOf()</code>는 객체를 아예 생성하지 않는다.<pre><code class="language-java">public static Boolean valueOf(boolean b) {
  return (b ? TRUE : FALSE);
}</code></pre>
만약 생성 비용이 큰 같은 객체가 자주 요청되는 상황일 때 정적 팩터리 메서드를 이용하면
성능 향상을 기대할 수 있다. </li>
</ul>
<p>또한 언제 어느 인스턴스를 살아있게 할지를 철저히 통제할 수 있다. (인스턴스 통제 클래스)
🤔 인스턴스를 통제하는 이유?</p>
<ul>
<li>Singleton 패턴으로 만들수 있다.</li>
<li>인스턴스화 불가로 만들 수 있다.</li>
<li>불변 클래스에서 동치인 인스턴스가 단 하나뿐임을 보장할 수 있다. 
(a == b일 때만 a.equals(b)가 성립)</li>
</ul>
<h3 id="3-반환-타입의-하위-타입-객체를-반환할-수-있는-능력이-있다">3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.</h3>
<p>반환할 객체의 클래스를 자유롭게 선택할 수 있게하는 엄청난 유연성을 제공한다.
이는 반환하는 타입을 인터페이스 타입으로 할 경우, 해당 인터페이스를 구현하는 
다른 타입의 객체들을 반환할 수 있음을 말한다. (상속)
특히 API를 만들 때 이 유연성을 응용하면 구현 클래스를 공개하지 않고도 그 객체를
반환할 수 있어 API를 작게 유지할 수 있다. 
이는 인터페이스 기반 프레임워크를 만드는 핵심 기술이기도 하다.
<img src="https://images.velog.io/images/new_wisdom/post/f55ed03e-10db-4e31-a45c-a2fa8d1e7d57/image.png" alt="">
특히 자바 컬렉션 프레임워크는 핵심 인터페이스들에 수정 불가, 동기화 등의 기능을 
덧붙인 총 45개의 유틸리티 구현체를 제공하는데, 
이 구현체 대부분을 단 하나의 인스턴스화 불가 클래스인 <code>java.util.Collectoins</code>에서 정적 팩터리 메서드를 통해 얻도록 했다.
Collection을 상속받는 모든 타입의 인스턴스가 리턴될 수 있는 것이다.</p>
<p>정적 팩터리를 사용하는 클라이언트는 얻은 객체를 인터페이스만으로 다루게 된다.</p>
<h3 id="4-입력-매개변수에-따라-매번-다른-클래스의-객체를-반환할-수-있다">4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.</h3>
<p>반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관없다.</p>
<ul>
<li><p>Example - <code>EnumSet</code>의 <code>noneOf()</code></p>
<pre><code class="language-java">public static &lt;E extends Enum&lt;E&gt;&gt; EnumSet&lt;E&gt; noneOf(Class&lt;E&gt; elementType) {
  Enum&lt;?&gt;[] universe = getUniverse(elementType);
  if (universe == null)
      throw new ClassCastException(elementType + &quot; not an enum&quot;);

  if (universe.length &lt;= 64)
      return new RegularEnumSet&lt;&gt;(elementType, universe);
  else
      return new JumboEnumSet&lt;&gt;(elementType, universe);
}</code></pre>
<p>예시로 <code>EnumSet</code> 클래스는 publi 생성자 없이 오직 정적 팩터리 메서드만 제공한다. 
만약 원소가 64개 이하이면 원소들은 long 변수 하나로 관리하는 
<code>RegularEnumSet</code>의 인스턴스를, 
65개 이상이면 long 배열로 관리하는 <code>JunboEnumSet</code>의 인스턴스를 반환한다.
클라이언트는 이 두 클래스의 존재를 몰라도 된다.</p>
</li>
</ul>
<h3 id="5-정적-팩터리-메서드를-작성하는-시점에는-반환할-객체의-클래스가-존재하지-않아도-된다">5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.</h3>
<p>이런 유연함은 서비스 제공자 프레임워크를 만드는 근간이 된다.
대표적인 서비스 제공자 프레임워크로는 JDBC가 있는데,
서비스 제공자 프레임워크에서의 제공자는 서비스의 구현체이다. 
그리고 이 구현체들을 클라이언트에 제공하는 역할을 통제하여, 
클라이언트를 구현체로부터 분리해준다.</p>
<h4 id="➕-서비스-제공자-프레임워크의-3개-핵심-컴포넌트">➕ 서비스 제공자 프레임워크의 3개 핵심 컴포넌트</h4>
<ul>
<li>서비스 인터페이스 : 구현체의 동작을 정의한다.</li>
<li>제공자 등록 API : 제공자가 구현체를 등록할 때 사용한다.</li>
<li>서비스 접근 API : 클라이언트가 서비스의 인스턴스를 얻을 때 사용한다.</li>
</ul>
<p>클라이언트는 서비스 접근 API를 사용할 때 원하는 구현체의 조건을 명시할 수 있다.
이 서비스 접근 API가 바로 서비스 제공자 프레임워크의 근간이 되는 <strong>정적 팩터리 메서드</strong>다.</p>
<p>이와 더불어 &#39;서비스 제공자 인터페이스&#39;라는 4 번째 컴포넌트가 쓰이기도 한다. 
이 컴포넌트는 인터페이스의 인스턴스를 생성하는 팩터리 객체를 설명해준다. </p>
<p>JDBC에서는 Connection이 서비스 인터페이스 역할, DriverManager.registerDriver가 제공자 등록 API 역할,
DriverManager.getConnection이 서비스 접근 API 역할,
Driver가 서비스 제공자 인터페이스 역할을 수행한다.</p>
<h2 id="단점">단점</h2>
<h3 id="1-상속을-하려면-public이나-protected-생성자가-필요하니-정적-팩터리-메서드만-제공하면-하위-클래스를-만들-수-없다">1. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.</h3>
<p>예시로 Collection 프레임뤄크의 유틸리티 구현 클래스들은 상속할 수 없다.</p>
<p>하지만 상속보다 컴포지션을 사용하도록 유도하고, 불변 타입으로 만들도록 
유도하므로 오히려 장점이 될 수도 있다.</p>
<h3 id="2-프로그래머가-찾기-어렵다">2. 프로그래머가 찾기 어렵다.</h3>
<p>사용자는 정적 팩터리 메서드 방식 클래스를 인스턴스화할 방법을 알아내야 한다.
때문에 정적 팩터리 메서드의 이름 규칙을 정해놓는다.</p>
<h4 id="명명-규칙">명명 규칙</h4>
<ul>
<li>from : 매개변수를 하나 받아 해당 타입의 인스턴스를 반환하는 형변환 메서드
ex) <code>Date d = Date.from(instant);</code></li>
<li>of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드
ex) <code>Set&lt;Rank&gt; faceCards = EnumSet.of(JACK, QUEEN, KING);</code></li>
<li>valueOf : from과 of의 더 자세한 버전
ex) <code>BingInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);</code></li>
<li>instance / getInstance : (매개변수를 받는다면) 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않는다. 
ex) <code>StackWalker luke = StackWalker.getInstance(options);</code></li>
<li>create / newInstance : instance / getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장한다.
ex) <code>Object newArray = Array.newInstance(calssObject, arrayLen);</code></li>
<li>getType : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. &quot;Type&quot;은 팩터리 메서드가 반환할 객체의 타입이다.
ex) <code>FileStore fs = Files.getFileStore(path);</code></li>
<li>newType : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. &quot;Type&quot;은 팩터리 메서드가 반환할 객체의 타입이다.
ex) <code>BufferedReader br = Files.newBufferedReader(path);</code></li>
<li>type : getType과 newType의 간결한 버전
ex) <code>List&lt;Complaint&gt; litany = Collections.list(legacyLintany);</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 배열의 깊은 복사와 얕은 복사]]></title>
            <link>https://velog.io/@new_wisdom/Java-%EB%B0%B0%EC%97%B4%EC%9D%98-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%99%80-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC</link>
            <guid>https://velog.io/@new_wisdom/Java-%EB%B0%B0%EC%97%B4%EC%9D%98-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%99%80-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC</guid>
            <pubDate>Wed, 10 Feb 2021 05:17:40 GMT</pubDate>
            <description><![CDATA[<h2 id="자바에서의-객체-복사">자바에서의 객체 복사</h2>
<p>자마에서 객체를 복사하는 유형에는 얕은 복사와 깊은 복사가 있다.</p>
<h3 id="얕은-복사">얕은 복사</h3>
<p>단순히 객체의 주소 값만을 복사하는 것이다. 
때문에 실제로는 하나의 주소 값만을 가지고 서로 간의 값은 바뀌지 않는다.
대부분 객체를 복사한다는 말은 얕은 복사가 아닌 깊은 복사를 의미한다. 
<strong>Example</strong></p>
<pre><code class="language-java">public class Array_Shallow_Copy{
    public static void main(String[] args)  {
        int[] arr1 = { 1, 2, 3};
        int[] arr2 = arr2;
    }
}</code></pre>
<p><code>=</code>  연산자는 <code>주소를 이어줌</code>을 의미하는데, 
위 예제는 a의 배열을 b배열로 <code>=</code> 연산자를 활용하여 대입했기 때문에 얕은 복사가 된다.
즉 같은 주소값을 가진다. (참조에 의한 복사)
때문에 arr2의 값을 수정하면 arr1의 값도 같이 수정된다.</p>
<h3 id="깊은-복사">깊은 복사</h3>
<p>객체의 실제 값을 새로운 객체로 복사한다. 
복사된 배열이나 원본 배열이 변경될 때 서로 간의 값은 바뀌지 않는다.</p>
<p>자바에서는 배열을 깊은 복사할 수 있는 여러가지 메서드를 제공하고 있다.</p>
<h4 id="obejctclone">Obejct.clone()</h4>
<pre><code class="language-java">public class Array_Copy_Clone{
    public static void main(String[] args)  {
        int[] a = { 1, 2, 3, 4 };
        int[] b = a.clone();
    }
}</code></pre>
<p>가장 보편적인 방법으로 깊은 복사를 할 때 사용된다.</p>
<p>But. 객체 배열의 경우 <code>clone()</code>을 사용하면 깊은 복사가 되지 않는다!
그 이유는 객체는 주소값을 가지고 있기 때문이다. (일반 자료형의 배열만 깊은 복사가 가능하다)
마찬가지로 2차원 배열의 경우도 각각의 row에 대한 주소값이 존재하기 때문에 깊은 복사가 되지 않는다.</p>
<p>또 해당 메소드는 객체의 클로닝을 위한 메소드인데
추가로 <a href="https://javacan.tistory.com/entry/31">객체 클로닝에 관하여</a> 글을 읽어보면 좋다.</p>
<h3 id="systemarraycopy">System.arraycopy()</h3>
<pre><code class="language-java">public class Array_Copy_ArrayCopy{
    public static void main(String[] args)  {
        int[] a = { 1, 2, 3, 4 };
        int[] b = new int[a.length];
        System.arraycopy(a, 0, b, 0, a.length);
    }
}</code></pre>
<p><code>System.arraycopy(src, srcPos, dest, destPos, a.length);</code> 형식으로 사용한다.</p>
<h3 id="일차원-객체-배열-복사하기">일차원 객체 배열 복사하기</h3>
<pre><code class="language-java">public static Pos[] deepCopy(Pos[] src){
    if(src == null) return null;
    Pos[] dest = new Pos[src.length];
    for(int i=0; i&lt;src.length; i++){
        src[i] = new Pos(src[i].a, src[i].b);
    }
    return dest;
  }</code></pre>
<p><code>for</code> 문을 돌 때마다 새로운 객체를 생성하여 직접 값을 넣어준다.
그래야 새로운 객체를 담은 다른 배열로 깊은 복사된 배열을 가질 수 있다.</p>
<h3 id="참고-자료">참고 자료</h3>
<ul>
<li><a href="https://coding-factory.tistory.com/548">[Java] 자바 배열을 복사하는 다양한 방법 (깊은복사, 얕은복사)</a></li>
<li><a href="https://hoho325.tistory.com/89">자바(java) 배열의 깊은 복사(deep copy)와 얕은 복사 완벽정리(1차원 배열, 2차원 배열, 객체 배열 복사)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OPP] 머리에 박제할라고 진짜 간단히 정리한 일급 컬렉션]]></title>
            <link>https://velog.io/@new_wisdom/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EB%A8%B8%EB%A6%AC%EC%97%90-%EB%B0%95%EC%A0%9C%ED%95%A0%EB%9D%BC%EA%B3%A0-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%A0%95%EB%A6%AC%ED%95%9C-%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98feat.-jojoldu%EB%8B%98%EC%9D%98-%EB%AA%85%EA%B8%80</link>
            <guid>https://velog.io/@new_wisdom/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EB%A8%B8%EB%A6%AC%EC%97%90-%EB%B0%95%EC%A0%9C%ED%95%A0%EB%9D%BC%EA%B3%A0-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%A0%95%EB%A6%AC%ED%95%9C-%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98feat.-jojoldu%EB%8B%98%EC%9D%98-%EB%AA%85%EA%B8%80</guid>
            <pubDate>Mon, 08 Feb 2021 15:29:30 GMT</pubDate>
            <description><![CDATA[<h3 id="일급-컬렉션">일급 컬렉션</h3>
<p>일급 컬렉션의 개념을 좀 더 정확히 짚고 넘어가야 할 것 같았다.
1차 리뷰어님께서 첨부해 주신 글을 저번에도 읽어보았으나
그 때까지는 이 글의 모든 개념을 파악하기 어려웠다.
때문에 훌라당 읽고 넘어갔지만 🥲
이번에 정독해보니 머릿 속에 개념과 목적이 좀 더 명확하게 잡혔다.</p>
<p>내 머릿 속에 박을라고 내가 이해한대로 진짜 간단하게 정리하는 글 ✍️</p>
<h3 id="참고-자료">참고 자료</h3>
<p><a href="https://jojoldu.tistory.com/412">일급 컬렉션 (First Class Collection)의 소개와 써야할 이유</a></p>
<h4 id="일급-컬렉션-1">일급 컬렉션?</h4>
<p>다른 멤버 변수가 없이 오로지 콜렉션만 포함한 객체.
한마디로 Collection을 클래스로 Wrapping 한 것이다.</p>
<h4 id="비즈니스에-종속적인-자료구조">비즈니스에 종속적인 자료구조</h4>
<p>collection의 값을 비즈니스 로직이 서비스 메소드에 들어가 있을 때 
값을 검증하는 메소드도 이 서비스 메소드에 들어가게 될 것이다.
만약 변경이 일어난다면 모든 코드와 도메인을 알고 있어야하므로 언제든지
문제의 발생 여지가 있는 로직이 되어버린다.
이는 객체지향 설계에 어긋난다.
해당 조건으로만 생성 할 수 있는 자료구조인 일급 컬렉션을 사용한다.</p>
<h4 id="불변-보장">불변 보장</h4>
<p><code>final</code> 예약어를 사용하라.
이는 불변을 금지하는 것이 아닌 재할당을 금지한다.</p>
<h4 id="상태와-행위를-한곳에서-관리">상태와 행위를 한곳에서 관리</h4>
<p>컬렉션 내의 어떤 상태별로 메소드를 실행하고 싶다 가정할 때 
로직이 밖으로 분리되어 있다면 상태에 따라 지정된 메소드 실행이 어렵다.</p>
<h4 id="이름이-있는-컬렉션">이름이 있는 컬렉션</h4>
<p>컬렉션에 이름을 붙일 수 있어 검색이 어렵고 명확한 표현이 불가능한 문제를 해결한다.</p>
]]></description>
        </item>
    </channel>
</rss>