아이템6. 불필요한 객체 생성을 피하라
2021-05-03 00:00:00 # Effective_Java
  • 똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다.
  • 정적 팩터리 메서드를 제공한다면 사용해서 불필요한 객체 생성을 피하자

생성 비용이 아주 비싼 객체들

  • 반복해서 필요하다면 캐싱하여 재사용하는 것이 좋다.
  • Unit Test Link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.regex.Pattern;

// 개선 전
class RomanNumerals {
static boolean isRomanNumeral(String s) {
return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" +
"X([CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}
}

// 개선 후
class RomanNumerals {
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})$");

static boolean isRomanNumeralByPattern(String s) {
return ROMAN.matcher(s).matches();
}
}

어댑터(Adapter)

  • 실제 작업은 뒷단 객체에 위임하고, 자신은 제2의 인터페이스 역할을 해주는 객체다.
  • 뒷단 객체 외에는 관리할 상태가 없으므로 뒷단 객체 하나당 어댑터 하나씩만 만들어지면 충분하다.
  • ex) Map 인터페이스의 Map.keySet() 은 새로운 인스턴스를 생성하는 것이 아닌 Map 객체 안의 키 전부를 담은 Set 뷰를 반환한다.

Auto Boxing

  • 프로그래멋가 기본 타입과 boxing 된 기본 타입을 섞어 쓸 때 자동으로 상호 변환해주는 기술
  • 기본 타입과 boxing 된 기본 타입의 구분을 흐리게 하지만, 완전히 없애는 것은 아니다.
1
2
3
4
5
6
7
// long과 Long
private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i; // 인스턴스가 계속 새로 생성되는 상황
return sum;
}
  • boxing된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 auto boxing이 숨어들지 않도록 주의하자!

결론

  • 객체 생성이 비싸니까 무조건 피하라는 말이 아니다.
  • 프로그램의 명확성, 간결성, 기능을 위해서 객체를 추가로 생성하는 것이라면 일반적으로 좋은 일이다.
  • 아주 무거운 객체가 아니고서야 자신만의 객체 pool을 만드는 일은 없도록 하자 (DB는 필요하다)
  • [아이템 50] 방어적 복사 와 대조되는 개념이다.
  • 불필요한 객체 생성은 그저 코드 형태와 성능에만 영향을 준다.