Search

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

생성일
2023/07/27 10:35
챕터
2장 - 객체 생성과 파괴

객체 재사용

동일한 기능의 객체를 매번 생성하여 사용하기보다는, 객체 하나를 재사용하는 편이 더 빠르고 세련된 방법일 수 있다.
특히 불변 객체는 언제든 재사용해도 동일한 결과를 얻을 수 있다.
String s = new String("bikini");
Java
복사
위와 같이 작성하게 되면 해당 문장이 실행될 때마다 String 인스턴스를 새로 생성하게 된다.
String s = "bikini";
Java
복사
이렇게 수정하면 매번 새로운 인스턴스를 만드는 대신, 하나의 String 리터럴 인스턴스를 사용하게 된다.
이와 같이 문자열 리터럴을 사용하는 모든 코드는 같은 객체를 재사용하는 것이 보장된다.
생성자 대신 정적 팩터리 메서드를 제공하면 불변 클래스를 제공하여 불필요한 객체 생성을 피할 수 있다.
Boolean(String) 생성자 대신 Boolean.valueOf(String) 팩터리 메서드를 사용하면, 생성자는 매번 새로운 인스턴스를 만들지만 팩터리 메서드는 재사용한다.
특히 생성 비용이 비싼 객체는 캐싱하여 재사용하길 권장된다.
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})$"); }
Java
복사
이와 같이 정규 표현식을 사용하는 경우에는, String.matches 메서드의 내부에서 정규표현식용 Pattern 인스턴스가 한번 사용되고 버려져 가비지 컬렉션의 대상이 된다.
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(); } }
Java
복사
그러니 이와 같이 객체를 재사용하여 빈번히 호출되는 상황의 성능을 상당히 개선할 수 있다.
오토박싱(auto boxing) 또한 불필요한 객체를 만들어낸다.
오토박싱은 기본 타입과 그에 대응하는 박싱된 기본 타입의 구분을 흐려주지만, 완전히 없애주지는 않는다.
private static long sum() { Long sum = 0L; for (long i = 0; i <= integer.MAX_VALUE; i++) sum += i; return sum; }
Java
복사
이 프로그램은 불필요한 오토박싱을 반복해서 수행하느라 성능이 무척 느려진다.
연산을 할 때는 가급적 박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토 박싱이 숨어들지 않도록 주의하자.
그렇다고 해서 객체 생성을 항상 피하려 하지는 말자.
아주 무거운 객체거나 생성 비용이 비싼 객체가 아닌 이상 단순히 객체 생성을 피하고자 객체 풀을 만들지 말자.
기존 객체를 재사용해야 한다면 새로운 객체를 만들지 말고, 방어적 복사를 통해 새로운 객체를 만들어야 한다면 기존 객체를 재사용하지 말자.