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

Posted by 김성철

Effective Java - 챕터6. 불필요한 객체 생성을 피하라

똑같은 기능의 객체는 매번 생성하기보다 객체 하나를 재사용하는 편이 나을때가 많다.  
  
	- 아래의 코드는 하지말하야 하는 코드  
	=================================================================================================================  
	String s = new String("hihihi");  
	=================================================================================================================  
  
위의 코드는 실행될때마다 새로운 String 인스턴스를 만든다  
완전히 쓸대없는 행위이며, 생성자에 넘겨진 "hihihi" 자체가 이 생성자로 만들어내려는 String 과 기능적으로 완전히 똑같다.  
이 문장이 반복문이나 빈번히 호출되는 메서드 안에 있다면 쓸데없는 String 인스턴스가 수백만개 만들어질 수도 있다.  
  
	- 개선된 방법  
	=================================================================================================================  
	String s= "hihihi";  
	=================================================================================================================  
  
위 코드는 새로운 인스턴스를 매번 만드는 대신 하나의 String 인스턴스를 사용한다.  
  
생성 비용이 아주 비싼 객체도 더러있다.  
비싼 객체가 반복해서 필요하다면 캐싱하여 재사용하길 권한다.  
다만 어떤객체가 비싼 객체인지는 알수 없다.  
  
예제로 아래의 정규식 코드를보자  
  
	=================================================================================================================  
	public boolean isRegexCheck(String s){  
		return s.matches("^(?=.)M*(C[MD])");  
	}  
	=================================================================================================================  
  
이 방식의 문자는 String.matches 메서드를 사용하는데 있다.  
String.matches 는 정규표현식으로 문자열 형태를 확인하는 가장 쉬운방법이지만, 성능이 중요한 상황에서는 반복해서 사용하기엔 적합하지 않다.  
  
	- 개선된 방법  
	=================================================================================================================  
	public class RegexCheck{  
		private static final Pattern REGEXSTRING = Pattern.compile(("^(?=.)M*(C[MD])"));  
  
		static boolean isRegexCheck(String s){  
			REGEXSTRING.match(s).matches();  
		}  
	}  
	=================================================================================================================  
  
위와같이 개선하면 빈번히 호출되는 상황에서 성능을 상당히 끌어 올릴수 있다.  
Pattern 인스턴스를 static final 필드로 끌어내서 이름도 지어주며 코드의 의미를 훨씬 잘 드러낼수 있다.  
  
또한 불필요한 객체를 만들어내는 방법으로 오토박싱이 있다.  
오토박싱은 long 로 될것을 굳이 Long 타입으로 하는것이다.  
아래의 코드를 보자  
  
	=================================================================================================================  
	private statric long sum(){  
		Long sum = 0L;  
		for(long i=0;i<Integer.MAX_VALUE; i++){  
			sum+=i;  
		}  
		return sum;  
	}  
  
	=================================================================================================================  
위 코드는 정확한 답을 내긴하지만 엄청 느리다.  
long 로 선언해야 할 변수를 Long 로 선언했기 때문에 불필요한 Long 인스턴스가 2의 31승개나 생성되기 때문이다.  
단순 속도계산만 해봐도 long 일때는 0.6초 Long일때는 6초가 걸린다.  
  
박싱된 기본 타입보다는 기본타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의해야 한다.  
  
객체 생성은 비싸니 피해야 한다가 아니다.  
거꾸로 아주 무거운 객체가 아닌 담으에야 단순히 객체 생성을 피하고자 객체풀을을 만들지 말자.