코딩하는 털보

이펙티브 자바, 아이템 6. 불필요한 객체 생성을 피하라 본문

Book/이펙티브 자바

이펙티브 자바, 아이템 6. 불필요한 객체 생성을 피하라

이정인 2021. 8. 13. 22:18

이펙티브 자바, 아이템 6. 불필요한 객체 생성을 피하라

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

  • String
    String s = new String("bikini"); 대신 String s = "bikini"
    전자는 매번 새로운 인스턴스를 만들지만 후자는 하나의 인스턴스를 사용하며 같은 문자열 리터럴을 사용하는 코드에서 같은 객체를 재사용한다.

  • 정적 팩터리 메서드를 제공하는 불변 클래스
    Boolean(String) 생성자 대신 Boolean.valueOf(String)

  • 생성 비용이 비싼 객체
    가능하다면 비싼 객체를 반복적으로 생성하지말고 정적 초기화 과정에서 직접 캐싱해두자.
    예를들면 String.matches() 메서드는 내부에서 Pattern 인스턴스를 만드는 데, 이 생성 비용이 높으므로 불변 Pattern 인스턴스를 직접 생성해 캐싱해두고 재사용하는 것.

    public class RomanNumerals {
    
        //Caching
        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을 초기화 할 수 있지만 코드는 복잡해지고 성능은 크게 개선되지 않는 경우가 많으므로 비추.

  • 어댑터 클래스
    Map 인터페이스의 keySet 메서드는 호출될 때마다 매번 같은 Set 인스턴스를 반환한다.
    Set 인스턴스를 수정하면 다른 객체가 따라서 바뀌기 때문에 keySet이 뷰 객체를 여러 개 만들 필요가 없다.

            Map<Integer, String> map = new HashMap<>();
            map.put(1, "A");
            map.put(2, "B");
            map.put(3, "C");
            map.put(4, "D");
    
            Set<Integer> integers = map.keySet();
            integers.remove(2);
            System.out.println(map);

    Set 인스턴스의 변경 가능성으로 인해 내가 사용하는 Set 인스턴스 또는 Map 인스턴스의 값을 확신하려면 인스턴스를 매번 복사하는 방어적 복사 방식을 사용해야한다.

            Map<Integer, String> map = new HashMap<>();
            map.put(1, "A");
            map.put(2, "B");
            map.put(3, "C");
            map.put(4, "D");
    
            Set<Integer> integers = new HashSet<>(map.keySet());
            integers.remove(2);
            System.out.println(map);
  • 오토 박싱 주의
    박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의.
    아래의 반복문은 Integer 인스턴스를 count만큼 생성한다. list.add(i)list.add(new Integer(i))와 같다.

            List<Integer> list = new ArrayList<>();
            int count = 100;
    
            for ( int i = 0; i < count; i++ ) {
                list.add(i);
            }
Comments