같은 기능의 객체를 매번 생성하는 것보다는 객체 하나를 생성해서 재사용하는 것이 메모리 양과 속도 측면에서 좋다.
예를 들어 다음의 String 생성을 예로 들 수 있다.
// 1. String 생성자 이용
String str = new String("test");
// 2. 문자열 상수를 이용해 생성
String str = "test";
위의 코드가 실행될 때마다 1번 같은 경우는 매번 String 객체를 생성한다. 같은 기능을 하는 객체이지만 매번 쓸데없는 String 객체가 생성된다는 단점이 있다.
그에 반해 2번은 "test"라는 String 객체를 하나 생성해두고 계속 같은 객체를 이용하게 한다.
(2번의 자세한 설명이 필요하다면 https://devlog-wjdrbs96.tistory.com/247 참고)
이러한 불필요한 객체 생성을 방지하기 위해 적용한 여러 방법들을 소개한다.
1. 생성자 대신 static factory method를 사용하기
// 1. 생성자 사용
Boolean bool = new Boolean(true);
// 2. static factory method 사용
Boolean bool2 = Boolean.valueOf(true);
위의 코드에서 1번 같은 경우에는 true 라는 값을 가진 Boolean 객체를 매번 생성하지만
2번 같은 경우에는 Boolean 클래스 안에 true로 미리 정의된 객체를 매번 반환하며 불필요한 객체 생성을 피할 수 있다.
(1번의 Boolean 생성자는 Java 9에서 deprecated 되었다.)
Boolean.valueOf() 함수는 내부적으로 다음과 같이 되어 있어 매번 같은 객체를 반환한다.
public final class Boolean implements java.io.Serializable, Comparable<Boolean> {
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
// ...
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
// ...
}
2. 생성 비용이 비싼 객체는 미리 만들어서(캐싱하여) 재사용한다.
public static boolean isNumber(String s) {
return s.matches("[0-9]*");
}
위 코드의 문제점은 String.matches()를 사용하는데 있다.
String matches() 함수는 내부적으로 임시 Pattern 객체를 생성해서 한번 쓰고 버리며 가비지 컬렉션 대상이 된다.
한번 사용에는 문제가 없을 수 있지만 반복 사용한다면 매번 임시 객체를 생성하기 떄문에 성능에 영향이 있을 수 있다
(Pattern은 정규표현식에 해당하는 유한 상태 머신(finite state machine)을 만들기 때문에 생성 비용이 높다)
위의 코드는 다음과 같이 변경하면 Pattern 객체를 재사용하기 때문에 성능에 있어 더 효율적이다.
private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]*");
public static boolean isNumber(String s) {
return NUMBER_PATTERN.matcher(s).matches();
}
참고 도서 : effective java
'Java' 카테고리의 다른 글
static method를 담은 Utility 클래스의 인스턴스화(객체 생성) 문제 (0) | 2022.04.03 |
---|
댓글