[Effective Java] 불필요한 객체 생성을 피하라

들어가며

똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 다음 코드를 보자.

1
String s = new String("song");

이 문장은 매번 새로운 String 객체를 생성한다. 이보다 다음 코드가 훨씬 좋다.

1
String s = "song";

이 코드는 새로운 인스턴스를 매번 만드는 대신 하나의 String 인스턴스를 사용한다. 나아가 이 방식을 사용한다면 같은 가상 머신 안에서 이와 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용함이 보장된다.

정규 표현식을 사용할 때도 다음과 같이 사용할 수 있다.

1
2
3
4
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})$");
}

이 코드를 다음과 같이 바꾼다.

1
2
3
4
5
6
7
8
9
public 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 isRomanNumeral(String s) {
return ROMAN.matcher(s).matches();
}
}

개선된 코드가 초기화된 이후 한번도 isRomanNumeral를 호출하지 않는다면 ROMAN 필드는 쓸데없이 초기화된 꼴이다. 이를 위해 Lazy Initialization을 사용할 수 있지만 코드는 복잡해지고 성능은 크게 개선되지 않는다.

불필요한 객체를 만들어내는 또 다른 예로 오토박싱이 있다. 다음 코드를 보자.

1
2
3
4
5
6
7
privte static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;

return sum;
}

이 프로그램은 불필요한 Long 타입 때문에 속도가 저하된다. 단순히 long 타입으로만 바꿔주면 개선할 수 있다. 박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의하자.

Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/04/Languages/Effective%20JAVA/item6/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.