개발 공부 기록하기/01. JAVA & Kotlin

짧은 코멘트와 함께하는 이펙티브 자바) #6 불필요한 객체 생성을 피하라

lannstark 2020. 9. 22. 08:42

짧은 코멘트

  1. 스프링을 사용하는 개발자라면, 생성비용이 아주 비싼 객체를 캐싱하고 있는 컴포넌트를 빈으로 등록해 활용할 수 있다.
  2. JPA를 사용할때는 Auto boxing을 사용할 수 있다. (DB column에 들어가는 null을 표현하기 위해) 하지만 연산이 들어가기 전에 가능한 빨리 primitive type으로 바꿔주는 것이 좋다. Long과 long 연산 단위가 수만회를 넘어가면 차이가 꽤 큰 것을 확인할 수 있다.
  3. String과 StringBuilder 역시 불필요한 객체 생성을 하는 예시라 할 수 있다.

 

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

String s = new String("JAVA");
String s = "JAVA";

첫 번째 코드보다 두 번째 코드가 좋다. 두 번째 코드는 새로운 인스턴스를 매번 만드는 대신 하나의 String 인스턴스를 사용하며, 같은 JVM안에서 이와 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용함이 보장된다

또 다른 예로 new Boolean(String) 보다는 Boolean.valueOf(String)이 불필요한 객체 생성을 막아줘서 좋은 코드이다

 

생성비용이 아주 비싼 객체도 있다
정규식을 검사할 때 사용되는 Pattern 객체가 그 예이다. 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})$";
  )
}

메소드가 처음 호출될 때 필드를 초기화하는 지연 초기화(lazy initialization)로 불필요한 초기화를 없앨 수는 있지만, 권하지 않는다

 

불필요하게 객체를 만들어 내는 또다른 예로는 Auto boxing이 있다. 오토 박싱은 기본 타입과 그에 대응하는 기본 타입의 구분을 흐려주지만, 완전히 없애주는 것은 아니다.

private static long sum() {
  Long sum = 0L;
  for (long i = 0; i <= Integer.MAX_VALUE; i++) {
    // 불필요한 Auto boxing이 계속 일어난다!
    sum += i;
  }
  return sum;
}

박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의하자!