IT/Programming / / 2023. 4. 28. 09:20

<Effective Java> RULE 5. 불필요한 객체는 만들지 말라

반응형
기능적으로 동일한 객체는 요할 때마다 만드는 것보다 재사용하는 편이 낫다.
 
//어느것이 더 효율적일까?

//1번
String s = new String("QueryBox");

//2번
String s = "QueryBox";
 

* new 로 String객체를 생성(1번)하면 다른 인스턴스를 만들때 처럼 heap 메모리에 객체가 생성된다.

String s = new String(“QueryBox”) 는 String 객체를 생성할 때마다 heap 영역의 어딘가에 “Querybox" 값이 매번 새롭게 저장되어 새로운 레퍼런스를 반환하게된다.

 

* String s = Querybox” 처럼 큰따옴표 방식(2번)으로 객체를 생성할 때도 heap 메모리에 객체가 생성된다. heap 에 저장되는 것 자체는 두 방식 모두 동일하지만, 큰 따옴표 방식은 heap 메모리 내에서 String Constant Pool에 저장된다.

“QueryBox” 라는 문자열이 큰따옴표 방식으로 생성된 적이 있으면 String Constant Pool 영역에 저장되고 또 같은 값을 “QueryBox” 라는 형식으로 생성한다면 기존에 생성된 “QueryBox” 와 같은 레퍼런스를 가지게된다.

 

즉 String 객체를 생성할 때 큰 따옴표 방식으로 생성해야만 동일한 문자열을 다시 String 변수에 할당할때 추가적인 객체 생성작업이 일어나지 않는다.

 

생성자와 정적 팩터리 메서드를 함께 제공하는 변경 불가능 클래스의 경우, 생성자 대신 정적 팩터리 메서드를 이용하면 불필요한 객체 생성을 피할 수 있다.

 

예를 들어 Boolean(String) 보다는 Boolean.valueOf(String) 쪽이 바람직하다.

//new Boolean(String)
public Boolean(String s) {
      this(toBoolean(s));
}
 
//Boolean.valueOf(string)
public static Boolean valueOf(String s) {
   return toBoolean(s) ? TRUE : FALSE;
}
 

 

어떠한 메소드 내부에서 동일한 객체를 항상 생성하는 로직이 있다면 정적 초기화 블록으로 생성 로직을 이동시켜 성능을 개선하는 것이 좋다.

public boolean isVacation() {
// 생산 비용이 높은 객체를 쓸데없이 생성한다.
   Calendar getCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   getCal.set(2017, Calenader.June, 1, 0, 0, 0);
   DATE vacationStart = gmtCal.getTime();
   getCall.set(2017, Calenader.July, 1, 0, 0, 0);
   DATE vacationEnd = gmtCal.getTime();
   return vacationDate.compareTo(vacationStart) >= 0 &&
  vacationDate.compareTo(vacationEnd) < 0;
}  
 

 

위 예제는 메서드가 호출될 때마다 Calendar, TimeZone, Date 객체를 쓸데없이 만들어 낸다.

이렇게 비효율적인 코드는 정적 초기화 블록(static initializer)을 통해 개선하는 것이 좋다.

private static final Date VACATION_START;
private static final Date VACATION_END;

//정적 초기화 블록
static {
   Calendar getCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   getCal.set(2017, Calenader.June, 1, 0, 0, 0);
   DATE vacationStart = gmtCal.getTime();
   getCall.set(2017, Calenader.July, 1, 0, 0, 0);
   DATE vacationEnd = gmtCal.getTime();
}
   
public boolean isVacation() {
   return vacationDate.compareTo(vacationStart) >= 0 &&
     vacationDate.compareTo(vacationEnd) < 0;
}  
 

 

또다른 불필요한 객체가 생성되는 경우는 jdk 1.5 부터의 autoboxing (자동 객체화)로 인해 발생하기 쉽다. 기본자료형과 객체 표현형을 섞어 쓸때 둘 간의 변환이 자동으로 이뤄진다.

//자동 객체화 예제
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
 

 

sum은 long이 아니라 Long으로 선언되어 있어 2^31 개의 쓸데없는 개체가 만들어 진다.

객체 표현형 대신 기본 자료형을 사용하고, 생각지도 못한 자동 객체화가 발생하지 않도록 유의 해야 한다.

 

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유