Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

5. 불필요한 객체의 생성을 피하자.

기능적으로 동일한 객체를 필요할 때마다 매번 새로 생성하기보다는 하나의 객체를 재사용하는 것이 좋을 때가 많다. 재사용을 하면 객체 생성에 소요되는 비용(시간과 자원)이 절감되므로 실행 속도가 더 빨라지고 코드도 보기 좋게 작성할 수 있다. 불변(immutable) 객체는 항상 재사용 가능하다.

해서는 안될 극단적인 예로 다음 코드를 생각해 보자

 
// 이렇게 하지 말자
String s = new String("stringette");

// 위 문장의 개선된 버전
String s = "stringette";

여기서는 실행될 때마다 새로운 인스턴스를 생성하지 않고 하나의 String 인스턴스를 사용하며, 같은 JVM에서 실행되는 어떤 코드에서도 동일한 문자열 리터럴(literal)을 갖도록 재사용 될 것이다.

불변 클래스의 불필요한 객체 생성을 막으려면 생성자보다는 static 팩토리 메소드를 사용하는 것이 좋다. 불변 객체의 재사용에 덧붙여, 객체(의 상태)가 변경되지 않는다면 가변(mutable) 객체도 재사용 가능하다.

해서는 안될 다른 예

 
public class Person {
	private final Date birthDate;
	
	// 다른 필드와 메소드 및 생성자는 생략
	// 이렇게 하지 말자!
	public boolean isBabyBoomer() {
		// 불필요한 객체 생성
		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) >= &&
				birthDate.compareTo(boomEnd) < 0;
	}
}

 

isBabyBoomer 메소드에서는 매번 호출될 때마다 하나의 Calendar 객체와 TimeZon 객체 및 두개의 Date 인스턴스를 불필요하게 생성한다. 아래 버전에서는 static 초기자(initializer)를 사용해서 그런 비효율적인 객체 생성을 막는다.

 
public Person {
	private final Date birthDate;
	// 다른 필드와 메소드 및 생성자는 생략
	/**
	 * 베이비 붐의 사작과 종료 일자.
	 */
	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) >= &&
				birthDate.compareTo(BOOM_END) < 0;
	}
}

 

이 개선된 버전에서는 Person 클래스가 초기화될 때 Calendar, TimeZone, Date 인스턴스를 한번만 생성한다.
성능 향상은 물로 코드도 더 명확하다

자바 1.5 이상의 버전에서는 불필요한 객체를 생성하는 새로운 방법이 있다. 오토박싱(autoboxing)이라고 하는데, 기본형 데이터를 이에 대응되는 박스화 기본형(boxed primitive) 클래스 객체로 자동 변환해주는 기능이다. 이와는 반대로 박스화 기본형 클래스 객체를 기본형으로 자동 변환해주는 것을 오토언박싱(autounboxing)이라 한다.

 
// 무지하게 느린 프로그램! 어디서 쓸데없는 객체가 생성되는지 찾아보자.
public static void main(String[] args) {
	Long sum = 0L;
	for (long i = 0; i < Integer.MAX_VALUE; i++) {
		sum += i;
	}
	System.out.println(sum);
}

의도하지 않은 오토 박싱이 생기지 않도록 주의하자!!

그러나 객체 생성은 많은 비용이 드니 피해야 한다는 의미로만 이 항목을 오해해서는 안 된다. 도리어 생성자에서 일을 거의 하지 않는 작은 객체의 생성과 재상용은 비용이 적게 든다. 프로그램의 명확성과 단순성 및 능력을 향상시키기 위해서라면 객체를 추가로 만드는 것도 좋은 일이다. 이와는 반대로, 우리가 직접 객체 풀(object pool)을 만들고 유지하여 객체 생성을 피하려는 방법은 좋지 않다. 단, 풀에 유지할 객체들이 대단히 무거워서 생성 비용이 많이 드는 것이라면 고려해 볼만하다.(데이터베이스 연결)

Posted by outliers
,