불변 클래스의 불필요한 객체 생성을 막으려면 생성자 보다는 static factory method를 사용하는 것이 좋다.

아래 예를 들어보자

 import java.util.*;

public class Person {
    private final Date birthDate;

    public Person(Date birthDate) {
        // Defensive copy - see Item 39
        this.birthDate = new Date(birthDate.getTime());
    }

    // Other fields, methods omitted

    // DON'T DO THIS!
    public boolean isBabyBoomer() {
        // Unnecessary allocation of expensive object
        Calendar gmtCal =
            Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomStart = gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomEnd = gmtCal.getTime();
        return birthDate.compareTo(boomStart) >= 0 &&
               birthDate.compareTo(boomEnd)   <  0;
    }
}


위의 코드를 보면 Calendar 객체와 TimeZone 객체 및 두 개의 Date 인스턴스를 불필요하게 생성한다.

윗 부분을 아래와 같이 고치면 좀 더 성능이 좋아진다.

 import java.util.*;

class Person {
    private final Date birthDate;

    public Person(Date birthDate) {
        // Defensive copy - see Item 39
        this.birthDate = new Date(birthDate.getTime());
    }

    // Other fields, methods

    /**
     * The starting and ending dates of the baby boom.
     */
    private static final Date BOOM_START;
    private static final Date BOOM_END;

    static {
        Calendar gmtCal =
            Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_START = gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_END = gmtCal.getTime();
    }

    public boolean isBabyBoomer() {
        return birthDate.compareTo(BOOM_START) >= 0 &&
               birthDate.compareTo(BOOM_END)   <  0;
    }
}


근데 위에 성능이 좋아지긴 하지만 항상 그런 건 또 아니다.
이유는 Calender 인스턴스의 생성비용이 많이 들기도 하지만 isBabyBoomer 메소드가 아예 호출되지 않는다면 BOOM_START와 BOOM_END가 쓸데없이 초기화되기 때문이다. 근데 이걸 배제하려면 lazy initialization을 해야하는데 그닥 권장하지 않는다.

자바에서는 오토박싱(autoboxing)이란 것으로 불필요한 객체를 생성하게 되는데 이건 기본형 데이터를 이에 대응되는 박스화 기본현 클래스 객체로 자동 변환을 해주는 기능이다. 이와 반대로 하는 것이 오토언박싱(autounboxing)이다.

Long sum = 0L;  <- 오토박싱된다.

문제는 이러면 엄청나게 느려질 수 있다. 그러니까 의도하지 않은 오토박싱이 생기지 않도록 주의해야 한다.

Posted by 서오석
,