[Effective Java] ch1 - item6. 불필요한 객체 생성을 피하라
똑같은 기능의 객체를 매번 생성하기 보다는 객체 하나를 재사용하는 것이 낫습니다. 불변 객체는 언제든 재사용할 수 있습니다.
String 클래스를 통한 객체 재사용
String str = new String("hello");
이처럼 실행될 때마다 새로운 인스턴스를 만드는 것보다
String str = "hello";
을 이용하면 하나의 인스턴스를 재사용 할 수 있습니다.
정적 팩토리 메소드를 제공하는 불변 클래스
Boolean엔 정적 팩토리 메소드를 제공하고 있다.
이처럼 Boolean isTrue = new Boolean(true);
생성자를 통해 인스턴스를 생성하는 건 아예 deprecated,
Boolean isTrue = Boolean.valueOf(true);
이를 사용하는 것이 권장됩니다.
가변객체는 재사용이 불가능 한가?
가변객체더라도 중간에 값이 변경되지 않음이 보장 된다면 충분히 재사용 가능합니다.
생성 비용이 비싼 객체는 재사용 효과가 좋다.
책에서는 정규표현식에 사용되는 Pattern
을 예시로 삼았습니다.
- 성능에 좋지 않은 Pattern 사용법
public class PatternExample { public static void main(String[] args) { String s = "IV"; boolean matches = isMatches(s); System.out.println(matches); } private static boolean isMatches(String s) { return s.matches("^(?=.)M*(C[MD] | D?C{0,3})" + "(X[CL] | L?X{0,3}) (I[XV] | V?I{0,3})$"); } }
- 성능이 향상된 Pattern 사용법
Pattern 인스턴스를 클래스 초기화(정적 초기화) 과정에서 직접 생성해 캐싱해두고 재사용한다.
public class PatternExample { private static final Pattern ROMAN = Pattern.compile( "^(?=.)M*(C[MD] | D?C{0,3})" + "(X[CL] | L?X{0,3}) (I[XV] | V?I{0,3})$" ); public static void main(String[] args) { String s = "IV"; boolean matches = isMatches(s); System.out.println(matches); } private static boolean isMatches(String s) { return ROMAN.matcher(s).matches(); } }
Pattern을 재사용하려고 했지만 전혀 사용하지 않는다면..
쓸데없이 Pattern을 초기화 한 꼴입니다.
이럴땐 isMatches()
가 처음 호출될 때 초기화하는 지연 초기화(lazy initialization) 방법이 있습니다.
코드가 복잡하고 성능에 크게 개선되지 않을 때가 많아 굳이 사용하진 않습니다.
어댑터 패턴과 인스턴스 재사용
Map
의 Set<K> keySet()
은 Map 객체 안의 키 전부를 담은 Set 뷰를 반환합니다.
반환된 Set<K>
는 가변입니다. 그러므로 반환된 객체 중 하나를 수정하면 모두 바뀝니다.
오토박싱을 주의하라
오토박싱을 한 wrong
메소드는 elapsed time :4467760500
기본타입을 쓴 right
메소드는 elapsed time :1110918709
으로 4배정도의 차이입니다.
오토박싱 한번으로 4배의 차이가 납니다.
이를 통해 박싱된 기본타입보다는 기본타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의합시다.
참고로 기본값 타입은 stored directly on the stack
이라고 합니다!
public class AutoBoxing {
public static void main(String[] args) {
wrong();
right();
}
private static void right() {
long start = System.nanoTime();
long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
long end = System.nanoTime();
System.out.println(" elapsed time :" + String.valueOf(end - start));
}
private static void wrong() {
long start = System.nanoTime();
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
long end = System.nanoTime();
System.out.println(" elapsed time :" + String.valueOf(end - start));
}
}
댓글남기기