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

2019. 3. 12. 01:06Java/Effective Java

반응형

똑같은 기능의 객체를 여러번 이용할거라면,
매번 생성자를 통해 인스턴스를 생성하는 것보다, 불변 객체(static final)로 재사용 하자.


불변 객체를 이용한다니? 어렵게 느껴질 수도 있겠지만, 우리가 아주 많이 사용하던 String의 리터럴 방식의 선언 역시 불변 객체를 이용하는 방식이에요.

String name = "jini";

우리가 늘상 사용하던 위와 같은 방식이 하나의 String 인스턴스를 사용하는 방식이며, 똑같은 문자열 리터럴 사용하는 모든 코드에서 재사용이 보장되기도 합니다.


똑같은 기능의 객체를 여러번 재사용할 경우에
이 기능을 static factory method로 대체한다면, 매번 생성자를 호출하여 객체를 생성하지 않을 수 있습니다.

즉,

Boolean b1 = new Boolean(true);

생성자 호출 방식으로 작성하는 것을

Boolean b2 = Boolean.valueOf(true);

위와 같은 형태로, factory method로 대체 할 수 있다는 것.
이 방식이 보다 세련된 방식이다. ( 최대한 생성자 호출을 줄여보자! )


특히 생성비용이 매우 큰 객체를 반복적으로 이용한다면,
caching하여 재사용하는 것이 좋다.

정규표현식을 활용한 예시로 재사용코드를 이용한 성능개선을 보여줄게요.
String의 matches메서드를 이용하여 휴대전화 여부를 정규표현식으로 체크하는 코드입니다.

public class Test {
	static boolean isPhoneNumber(String s) {
		return s.matches("^01(?:0|1|[6-9])[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$");
	}
	public static void main(String[] args) {
		String s1 = "010.1231.1234",
				s2 = "019-111-2231",
				s3 = "02-2343-2132";
		System.out.println(isPhoneNumber(s1));
		System.out.println(isPhoneNumber(s2));
		System.out.println(isPhoneNumber(s3));
	}
}

사실 이렇게 String이 내장하고 있는 matches 메서드를 이용해도 기능 구현에는 문제는 없다.

그러나, 이 메서드는 내부적으로 Pattern인스턴스를 생성하여 기능을 동작시킵니다.
isPhoneNumber 메서드가 빈번히 요청될수록 성능은 저하될 것입니다.


이를 개선하고 싶다면??
Pattern 인스턴스를 caching( = static final로 설정 )하면 된다!

private static final Pattern PHONENUMBER_PATTERN =
		Pattern.compile("^01(?:0|1|[6-9])[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$");

static boolean isPhoneNumber(String s) {
	return PHONENUMBER_PATTERN.matcher(s).matches();
}

그러나, 복잡하지 않은 작은 객체를 생성하고 회수하는 일이 JVM에 큰 부담을 준다는 의미는 아니다.

새로운 객체를 만들어야할 때에는 기존의 객체를 재사용하는 것은 좋지 않은 방식이다.
( 잘못된 복사로 인하여 문제가 발생할 수 있다. )

Item 6 에서 말하는, 불필요한 객체 생성을 피하자의 핵심은
같은 기능의 객체를 이용하고자 할 때, 굳이 매번 생성하지 말고, 객체 하나를 재사용하자는 의미입니다.

다른 기능의 객체를 만들어야한다면, 생성자로 새로 생성하는 것이 맞다.

728x90
반응형