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

노을·2023년 1월 17일
0

이펙티브 자바

목록 보기
6/14
post-thumbnail

⭐ 불필요한 객체를 생성하는 경우 & 해결방법



☑️ 무분별한 String 객체 생성


String s = new String("bikini");

이렇게 newString 객체 생성을 하는 경우엔 이 문장이 실행될 때 마다 새로운 객체가 만들어진다.

String s1 = new String("bikini");
String s2 = new String("bikini");

System.out.println("s1 equals s2 " + s1.equals(s2)); //true
System.out.println("s1 == s2 " + s1 == s2); //false

s1s2는 값도 같고 기능적으로 동일하지만 s1 == s2 했을 때 false가 나온다.


이를 해결하기 위해서는 값이 같다면 하나의 인스턴스를 사용하면 된다.

String s1 = "bikini";
String s2 = "bikini";

System.out.println("s1 equals s2 " + s1.equals(s2)); //true
System.out.println("s1 == s2 " + s1 == s2); //true

이렇게 하면 같은 객체를 재사용할 수 있게 된다.



☑️ 팩터리 메서드가 있는데 생성자를 사용하는 경우

Boolean aBoolean = new Boolean("hello"); //사용자제 API

처럼 Boolean 생성자로 객체를 만들 수 있지만
불필요한 객체 생성을 방지하기 위해 Boolean.valueOf(String string)을 사용하자.

Boolean aBoolean = Boolean.valueOf("hello");



☑️ 생성 비용이 비싼 객체를 반복해서 쓰는 경우

생성 비용이 비싼 객체가 있다면 캐싱해서 사용해야 한다.

예를 들면 String.matches 메서드가 있다.

static boolean isRomanNumeralSlow(String s) {
    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}

s.matches를 실행하면 Pattern 인스턴스가 만들어지는데 한 번 쓰여지고 버려진다.


이를 해결하기 위해 Pattern 인스턴스를 미리 하나 만들어두고 미리 캐싱해서 사용하는 방법이 있다.

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 isRomanNumeralFast(String s) {
    return ROMAN.matcher(s).matches();
}



☑️ 오토박싱

오토 박싱 : 기본 타입과 박싱된 기본 타입을 섰어 쓸 때 자동으로 상호 변환해주는 기술

private static long sum() {
    Long sum = 0L; //sum은 long이 아니라 Long 타입
    for (long i = 0; i <= Integer.MAX_VALUE; i++)
        sum += i;
    return sum;
}

현재 sumlong이 아니라 Long 타입이기 때문에 sum += i이 실행될 때 마다 Long 객체가 새로 만들어지고 있는 것이다. 총 Long 객체는 Integer.MAX_VALUE 만큼 만들어졌다.
➡️ 기본 타입을 사용하자!



⭐ 주의할 점

객체 생성을 무조건 피해야 한다고 생각하지 말자.
요즘 JVM 가비지 컬렉터는 최적화가 잘 되어 있어서 억지로 객체 풀을 만드는 것은 바람직하지 못하다. 자체 객체 풀은 코드를 헷갈리게 만들고 메모리 사용량을 늘리며 성능을 떨어뜨리기 때문에 조심해서 사용하자!

0개의 댓글