String s = new String("bikini");
이렇게 new
로 String
객체 생성을 하는 경우엔 이 문장이 실행될 때 마다 새로운 객체가 만들어진다.
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
s1
과 s2
는 값도 같고 기능적으로 동일하지만 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;
}
현재 sum
은 long
이 아니라 Long
타입이기 때문에 sum += i
이 실행될 때 마다 Long
객체가 새로 만들어지고 있는 것이다. 총 Long
객체는 Integer.MAX_VALUE
만큼 만들어졌다.
➡️ 기본 타입을 사용하자!
객체 생성을 무조건 피해야 한다고 생각하지 말자.
요즘 JVM 가비지 컬렉터는 최적화가 잘 되어 있어서 억지로 객체 풀을 만드는 것은 바람직하지 못하다. 자체 객체 풀은 코드를 헷갈리게 만들고 메모리 사용량을 늘리며 성능을 떨어뜨리기 때문에 조심해서 사용하자!