JAVA/Effective Java

객체의 생성과 삭제 - 규칙 5 불필요한 객체는 만들지 말라

반응형

기능적으로 동일한 객체는 필요할 때 마다 만들지 않고 재 사용하는 것이 
더욱 효율적이다.

사례 1.
new String("str") 보다 "str"을 사용하라.

 반복문 속에서 String 문장을 사용해야 할 때 new String("test")를 통해서 객체를 새로 생성하는 것이 아니라, "test"와 같이 그 자체가 String 객체인 문장을 사용하는 것이 좋다.

그 이유는 다음과 같다.

(출처 : http://blog.vjvj.net/2017/04/effective-java-5.html)

두 가지 경우 모두 생성 시 heap 메모리에 객체가 생성된다. 
하지만 "test"와 같이 String 객체를 만드는 경우에는 heap에 String Constant Pool영역에 생성된다. 

그래서 사용자가 "test"라는 객체를 생성하여 작업하려 할때 String Constant Pool영역에서 존재여부를 확인하고 

해당 레퍼런스를 가지고 사용하게 된다.  

하지만 new String("test")에 경우에는 매번 새로운 heap 영역에 새로운 객체를 생성하기 때문에 좋지않다.

사례 2.
immutable class를 사용해야 하는 경우에는 생성자 대신 정적 팩토리 메서드를 이용하면 불필요한 객체 생성을 피할 수 있다.

immutable class인 boolean을 사용해야 하여 참, 거짓을 판단하고 싶을 때 두가지 방식으로 boolean 객체를 만든다고 생각하여 보자.



1
2
new Boolean("st".equals("st"));
Boolean.valueOf("st".equals("st"));
cs



위 두가지 경우에서 첫 번째 경우에는 Boolean 객체를 계속 생성하고, 두 번째 방법은 정적 팩토리 메서드 패턴을 이용하여 기존에 생성되어 있는 Boolean 객체를 반환 받기 때문에 더욱 효율적이다.

사례 3
변경 가능한 객체에 경우에 다음과 같은 경우를 피해야 한다.



1
2
3
4
5
6
7
8
public class Babo {
    private final Date birthDay = new Date(201711);
    
    public boolean isTodayBirth() {
        Date today = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime();
        return birthDay.compareTo(today) == 0;
    }
}
cs




위에 경우 isTodayBirth() 메소드가 실행 될때 마다 Calendar와 TimeZone 객체가 생성되기 때문에 좋지 않다.

만약 이 메서드가 자주 사용되는 것일 경우에 static 블록에 Calendar와 TimeZone 객체를 생성되게 하고 가져다가 쓰면 계속 만들어지는 문제는 해결될 것이다.



1
2
3
4
5
6
7
8
9
10
11
private final Date birthDay = new Date(201711);
    
private static final Date today;
    
static {
    today = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime();
}
    
public boolean isTodayBirth() {
    return birthDay.compareTo(today) == 0;
}
cs



하지만 만약, 한번도 isTodayBirth() 호출되지 않을경우에는 쓰지 않는데 구태여 만들어 버리니 오히려 더 낭비가 될 수 있다.

이럴때는 Lazy 방식으로 정말 필요할 때만 실행되도록 지정해 주어야 한다.

사례 4
java 1.5 부터 나온 자동 객체화 (autoboxing)은 Wapper Class와 primitive type을 섞어서 사용할 수 있게 해주는 기능이다. 

두 개 사이는 자동 변환이 되기때문에 괜찮을 것 같지만,
이 자동변환 자체가 성능을 많이 좌지우지 하기 때문에 조심해야 한다.

Long은 하단의 설명과 같이 long를 클래스로 감싼 클래스이기에 생성하기 위해서는 객체가 계속 생성된다.

그러므로 항상 특별한 경우가 아닌경우에는 기본 자료형(primitive type)을 사용할 것.

(기본 자료형은 객체가 아니기에 null이 안되기에 기본형을 감싼 클래스인 wrapper class를 사용하면 된다.)
기본형   대응 래퍼 클래스 
byte     Byte 
short    Short 
int      Integer 
long     Long 
float    Float 
double   Double 
char     Char 
boolean  Boolean


1
2
3
4
Long sum = 0L;
for (long l = 0; i < Integer.MAX_VALUE; i++) {
 sum += i;
}
cs




그렇다고 무분별한 객체 생성을 막는다고, 객체 풀을 만들어서 사용하는 것을 권하지 않는다.

데이터베이스 연결과 같은 경우에는 객체를 새로 만드는 것이 더 비용이 크기 때문에 객체 풀로 관리 하는 것이 좋으나 대부분의 경우가 객체 풀 관리보다는 새로 만드는 것이 더 유용하다.





출처 : 조슈아 블로크, 『 Effective Java 2/E』, 이병준 옮김, 인사이트(2014.9.1), 규칙5 인용.



반응형