6. 불필요한 객체 생성을 피하라
📚 요약
똑같은 기능의 객체를 매번 새로 생성하지 말고, 불변 객체는 한 번 만들어서 재사용하기
생성 비용이 비싼 객체(예: 정규표현식 패턴)는 정적 필드에 캐싱하여 재활용하고, 오토박싱처럼 불필요한 객체 생성을 유발하는 기능은 주의해서 사용하기
객체 재사용은 프로그램의 성능을 향상시키지만, 방어적 복사가 필요한 상황에서는 새 객체를 만드는 것이 더 안전하다
불필요한 객체 생성이란?
프로그램에서 똑같은 물건(객체)을 계속 새로 만드는 대신, 이미 만들어진 물건을 다시 사용하는 것이 좋다
왜 중요할까?
새로운 물건을 만들 때마다 컴퓨터는 일을 더 많이 해야 하고, 메모리도 더 많이 사용한다 이는 프로그램을 느리게 만들 수 있다
🚫 나쁜 방법: 계속 새로 만들기
문자열을 매번 새로 만드는 예시
// 나쁜 방법: 같은 문자열을 계속 새로 만들기
for (int i = 0; i < 1000; i++) {
String name = new String("토끼"); // 매번 새로운 "토끼" 문자열 객체 생성
// name으로 작업 수행
}
패턴을 매번 새로 만드는 예시
// 나쁜 방법: 패턴을 매번 새로 만들기
public class 로마숫자검사기 {
static boolean 로마숫자인지확인(String s) {
return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" +
"(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})"); // 매번 새로운 패턴 객체 생성
}
}
✅ 좋은 방법: 객체 재사용하기
문자열 상수 사용하기
// 좋은 방법: 문자열 상수 사용
String name = "토끼"; // 한 번만 만들고
for (int i = 0; i < 1000; i++) {
// name을 계속 재사용
}
패턴 객체 재사용하기
//좋은 방법: 패턴 객체를 만들어 재사용
public class 로마숫자검사기 {
// 클래스가 로드될 때 한 번만 패턴 객체 생성
private static final Pattern 로마숫자패턴 = Pattern.compile(
"^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})");
static boolean 로마숫자인지확인(String s) {
return 로마숫자패턴.matcher(s).matches(); // 미리 만든 패턴 객체 재사용
}
}
🎁 다양한 재사용 방법들
팩토리 메서드 사용하기
// 생성자 대신 팩토리 메서드 사용
// 나쁜 방법
Boolean b1 = new Boolean("true"); // 생성자 사용 (비권장)
// 좋은 방법
Boolean b2 = Boolean.valueOf("true"); // 팩토리 메서드 사용 (권장)
불변 객체는 항상 재사용 가능
변하지 않는 객체(불변 객체)는 언제든지 재사용해도 안전하다 예를 들어, 숫자나 문자열 같은 것들이 불변 객체다
오토박싱 조심하기
기본 타입(int, long 등)과 래퍼 타입(Integer, Long 등)을 섞어 쓸 때 발생하는 자동 변환(오토박싱)은 불필요한 객체를 많이 만들 수 있다
// 나쁜 방법: Long 타입 사용으로 불필요한 객체 생성
public class 합계 {
private static long 더하기() {
Long sum = 0L; // Long 타입 사용 (객체)
for (long i = 0; i <= 1000000; i++) {
sum += i; // 매번 새로운 Long 객체 생성됨
}
return sum;
}
}
// 좋은 방법: long 타입 사용
public class 합계 {
private static long 더하기() {
long sum = 0L; // long 타입 사용 (기본 타입)
for (long i = 0; i <= 1000000; i++) {
sum += i; // 객체 생성 없음
}
return sum;
}
}
📝 불필요한 객체 생성을 피하는 방법 정리
상수 사용하기: 같은 값을 여러 번 사용할 때는 상수로 만들어 재사용하기
정적 팩토리 메서드 사용하기: 생성자 대신 정적 팩토리 메서드를 사용하면 객체 재사용이 가능할 때가 많다
불변 객체 사용하기: 변하지 않는 객체는 안전하게 재사용할 수 있다
비싼 객체는 캐싱하기: 만들기 어려운 객체는 한 번 만들어 계속 재사용하기
기본 타입 사용하기: 가능하면 래퍼 타입보다 기본 타입을 사용하기
⚖️ 주의할 점
모든 객체를 재사용하려고 하면 안된다
객체 풀(많은 객체를 미리 만들어 두는 것)은 복잡하고 오히려 성능을 저하시킬 수 있다
데이터베이스 연결 같이 정말 만들기 비싼 객체가 아니라면 객체 풀은 피해라
🤔 느낀 점
프로그램을 작성할 때 단순히 '작동하게' 만드는 것을 넘어, 어떻게 하면 더 효율적으로 자원을 활용할 수 있을지 고민하는 자세가 중요하다는 것을 느꼈다 불변 객체의 가치와 효용에 대해서도 더 깊이 생각해볼 수 있었다
🧩 어려웠던 점
어떤 상황에서 객체를 재사용해야 하고, 어떤 상황에서는 새로 생성해야 하는지 구분하는 것이 명확하지 않아서 좀 이해하는데 어려웠다 뒤에(아이템50) 나올 방어적 복사가 필요한 상황과 객체 재사용이 효율적인 상황 사이의 경계를 어떻게 구분해야할지 고민해봐야 할거같다
Last updated