본문 바로가기

이펙티브 자바

불필요한 객체 생성을 피하라

똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다.
1. 예를 들면 String 객체를 만드는 방법은 두 가지가 있다. 첫 번째는 생성자를 통해서 만드는 것이다.

String str = new String("str");

두 번째 방법은 새로운 인스턴스를 매번 만드는 게 아니라 하나의 인스턴스를 재사용하는 방법이다.

String str = "str";

처음에는 두 개의 코드를 보고 같다고 생각할 수 있다. 하지만 두 코드 사이에는 큰 차이가 있다. 코드 예시를 보자.

String str = new String("str");
String str1 = new String("str");
//처음 출력
System.out.println(str == str1);

String sstr = "str";
String sstr1 = "str";
//두 번째 출력
System.out.println(sstr == sstr1);

처음 출력값은 false이고 두 번째 출력값은 true이다. 왜 이렇게 나올까? 이유는 첫 번째 생성자를 통해서 객체를 생성하면 생성할 때마다 Heap 영역에 쌓이게 된다. 말을 쉽게 하면 이미 같은 값이 있든 말든 무조건 새롭게 생성한다는 것이다. 그러면 처음 출력은 값은 같지만 다른 객체이기 때문에 false가 출력이 된다. 두 번째 생성자를 사용하지 않는 방법은 Heap 영역 안에 있는 String Constant Pool에 생기게 된다. Heap 영역과 차이는 String Constant Pool에 이미 같은 문자가 존재하면 새롭게 객체를 생성하지 않고 기존에 객체를 참조한다. 그렇기 때문에 두 번째 출력이 true가 된다.

2. Boolean 타입을 만들 때도 생성자를 통해 만드는 것보다 Boolean.valueof() 정적 팩토리 메서드를 사용해서 만드는 게 더 좋다.

3. 생성 비용이 아주 비싼 객체는 초기화 과정에서 직접 생성해 캐싱 해두고, 필요할 때마다 메서드를 통해 재사용한다.

private static final Pattern Roman = Pattern.compile("정규식");
static boolean isRomanNumeral(String s) {
        return Roman.matcher(s).matches();
}

4. 박싱된 기본 타입보다는 기본 타입을 사용하고 의도치 않은 오토박싱을 주의하자