위의 방법은 실행될 때 마다 String 인스턴스를 새로 만들게 된다. String은 “불변”이기 때문에 위 방법으로 반복이라도 돌면 똑같은 기능을 하는 문자열을 수백 수천개를 만들게 될 수 있게되며 절대 해서는 안되는 행동이다.
String hello = "안녕"
위 방법으로 실행하면 가상머신 안에 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용함이 보장된다.
근데 String은 왜 불변일까?
반대로 String이 가변이면? 같은 참조를 가지는 객체의 값을 변경할 수 있게 된다. 이 말은 같은 참조 & 다른 값 이라는 상황을 만들 수 있기 때문에 재사용이 불가능해진다. 따라서 객체 공유를 통한 재사용 목적인 String Pool 을 사용할 수 없게 된다.
또한 가변 상태의 객체는 같은 문자열 리터럴을 가지더라도 객체를 매번 생성해야 한다. String이 많이 사용되는 메서드나 반복문에서 쓸데없는 인스턴스가 많이 만들어질 수도 있다는 뜻을 가지고 있다. 즉 애플리케이션 성능에 안좋은 영향을 미친다.
for(int i=0; i<1000000; i++){ String str = new String("newString");}
생성자 대신 정적 팩터리 메소드를 이용해 불필요한 객체 생성을 피할 수 있다.
Integer i = 100 // 1
Integer i = Integer.valueOf(100) // 2
// 3
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
비싼 객체가 반복해서 필요하다면 캐싱하여 재사용하라
import java.util.regex.Pattern;
public class RomanNumerals {
// 매번 이 패턴을 적용하면 비용도 많이들고 수행 시간도 느리다.
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}$");
}
// 객체를 재사용해서 성능을 올리자
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(); }
}
오토박싱을 조심하자
public static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i // 불필요하게 오토박싱이 계속해서 일어난다.
}
}
인스턴스를 그만큼 계속해서 만들기 때문에 단순해도 상당히 시간이 걸린다.
따라서 박싱된 기본 타입보다는 기본 타입을 생성하고 의도치 않은 오토박싱이 숨어들지 않도록 주의하자.
즉 주의해야 할 점은 위의 세가지는 특수한 상황이다.
같은 오브젝트 / 불 필요하게 객체를 생성할 필요가 없으니 생성하지 말라는 뜻이다.
만드는데 무거운 객체들은 재사용 하는것을 권장하는 것이다.
불필요하게 많은 객체들을 만드는걸 조심하자 일반적인 경우에 객체를 만들지 말라는 소리는 절대 아니다 !