반응형
아이템 6 - 불필요한 객체 생성을 피하라 - 핵심 정리
이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.
주의할 점은 객체 생성은 비싸니 피하라 는 뜻이 아니다.
불필요하게 동일한 기능을 함에도 여러번 생성하는 경우가 있는 이런 상황을 피하도록 하자.
문자열
public class Strings {
public static void main(String[] args) {
String hello = "hello";
//TODO 이 방법은 권장하지 않습니다.
String hello2 = new String("hello");
String hello3 = "hello";
System.out.println(hello == hello2); // false - 같은 문자열임에도 불구하고 인스턴스가 다르기 때문에 false로 나온다
System.out.println(hello.equals(hello2)); // true
System.out.println(hello == hello3); // true
System.out.println(hello.equals(hello3)); // true
}
}
문자열은 "" 를 통해 생성한다.
하지만 new String("hello"); 을 통해 생성한다면 잘못 사용하고 있는 것이다.
JVM 은 내부적으로 문자열을 pool 에 캐싱하고 있다.
어디선가 동일한 문자열을 참조하려고 하면 새로 만드는 것이 아닌 상수들의 pool 에서
동일한 문자열을 참조하는 방법으로 재사용하게 된다.
하지만 new String 을 사용하면 강제적으로 새로운 객체를 생성하게 된다.
만약 같은 문자열임을 판단하는 경우에는 equals 를 사용하도록 하자.
정규 표현식
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 void main(String[] args) {
boolean result = false;
long start = System.nanoTime();
for (int j = 0; j < 100; j++) {
//TODO 성능 차이를 확인하려면 xxxSlow 메서드를 xxxFast 메서드로 바꿔 실행해보자.
result = isRomanNumeralSlow("MCMLXXVI");
}
long end = System.nanoTime();
System.out.println(end - start);
System.out.println(result);
}
}
정규식 같은 경우는 한번 생성할 때 만드는 비용이 좀 비싸다.
즉, Cpu 자원을 꽤 사용한다는 뜻이다.
자주 사용하는 패턴이고, 정규표현식이고, 여러번 사용된다면 필드로 선언해서 사용하는 걸 권장한다.
오토박싱(auto boxing)
프리미티브 타입을 wrapper 타입으로 변경할때 오토박싱 이 일어나고,
wrapper 타입을 프리미티브 타입으로 변환하는 과정을 언박싱 이라고 한다.
이러한 오토박싱, 언 박싱 을 런타임에 JVM 이 자동으로 처리해준다.
불필요하게 오토박싱 이 일어나는 경우 인스턴스가 계속 만들어지게 된다.
즉, long -> Long 으로 변환할 때 새로운 인스턴스가 만들어지게 된다.
public class Sum {
private static long sum() {
// TODO Long을 long으로 변경하여 실행해 보세요.
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
public static void main(String[] args) {
long start = System.nanoTime();
long x = sum();
long end = System.nanoTime();
System.out.println((end - start) / 1_000_000. + " ms.");
System.out.println(x);
}
}
위 코드에서 불필요하게 오토박싱 이 일어나지 않게끔 코드를 수정하면 성능이 많이 개선된 걸 확인할 수 있다.
반응형
'개발 공부 > Java' 카테고리의 다른 글
이펙티브 자바 아이템 7 - 다 쓴 객체 참조를 해제하라 - 완벽 공략 (0) | 2022.10.07 |
---|---|
이펙티브 자바 아이템 6 - 불필요한 객체 생성을 피하라 - 완벽 공략 (1) | 2022.09.23 |
이펙티브 자바 아이템 5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 - 완벽 공략 (1) | 2022.09.22 |
이펙티브 자바 아이템 5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 - 핵심 정리 (1) | 2022.09.21 |
이펙티브 자바 아이템 4 - 인스턴스화를 막으려거든 private 생성자를 사용하라 - 핵심 정리 (0) | 2022.09.20 |
댓글