개요
최근 프로젝트에서 멀티스레드 환경에서 동시성 문제를 해결하는 방법을 고민하던 중, 불변 객체(Immutable Object)를 사용하는 것이 코드 안정성에 큰 도움이 된다는 점을 깨달았다. 여러 스레드가 동일한 객체를 참조할 때, 객체의 상태가 변하지 않으면 추가적인 동기화 처리가 필요 없기 때문이다. 그래서 이번 글에서는 자바에서 불변 객체를 만드는 방법과 그 장점을 소개하려 한다.
불변 객체란 무엇인가?
불변 객체란, 한 번 생성된 후 내부 상태가 절대 변경되지 않는 객체를 말한다. 즉, 객체가 생성된 이후에 그 속성들은 수정할 수 없다. 대표적으로 자바의 String 클래스가 불변 객체로 설계되어 있다. 불변 객체는 주로 멀티스레드 환경에서 동시성 문제를 해결하는 데 매우 유용하다.
불변 객체의 장점
불변 객체는 여러 장점을 가지고 있다.
- 동시성 문제 해결: 불변 객체는 상태가 변경되지 않기 때문에 여러 스레드에서 동시에 사용해도 안전하다. 추가적인 동기화 처리가 필요 없다.
- 안정성과 신뢰성: 객체가 변하지 않기 때문에 다른 코드에서 실수로 객체의 상태를 변경할 위험이 없다.
- 간편한 테스트: 불변 객체는 테스트가 용이하다. 상태가 변하지 않기 때문에 예상된 값이 항상 동일하게 유지된다.
자바에서 불변 객체 만드는 방법
불변 객체를 만들기 위해서는 몇 가지 규칙을 따라야 한다.
모든 필드를 final로 선언하기
필드를 final로 선언하면, 해당 필드는 객체가 초기화될 때 한 번만 값을 설정할 수 있다.
public class ImmutableUser {
private final String name;
private final int age;
public ImmutableUser(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
객체 상태를 변경하는 메서드를 제공하지 않기
불변 객체에서는 setter 메서드를 만들지 않는다. 위의 ImmutableUser 클래스는 이름과 나이를 설정한 후 변경할 수 없다.
필드가 참조 타입일 경우, 방어적 복사하기
만약 필드가 참조 타입(예: 배열, 리스트, 객체)이라면, 방어적 복사(defensive copy)를 통해 원본 데이터가 변경되지 않도록 해야 한다.
public class ImmutablePerson {
private final String name;
private final List<String> hobbies;
public ImmutablePerson(String name, List<String> hobbies) {
this.name = name;
this.hobbies = new ArrayList<>(hobbies); // 방어적 복사
}
public String getName() {
return name;
}
public List<String> getHobbies() {
return new ArrayList<>(hobbies); // 방어적 복사
}
}
위 예제에서 hobbies 리스트를 외부에서 수정할 수 없도록 생성자와 getter 메서드에서 방어적 복사를 적용했다.
불변 객체의 사용 사례
불변 객체는 다양한 상황에서 유용하게 쓰인다. 대표적인 사용 사례는 다음과 같다:
- 멀티스레드 환경: 불변 객체는 상태가 변하지 않기 때문에 멀티스레드 환경에서 안전하게 사용할 수 있다. 스레드 간에 동기화를 신경 쓸 필요가 없어 성능이 향상된다.
- 값 객체(Value Object): 값 객체는 그 자체가 하나의 값으로 사용되며, 주로 식별자(ID)나 좌표, 날짜 등과 같은 개념을 나타낸다. 불변 객체로 설계하면 값 객체의 신뢰성을 높일 수 있다.
- 함수형 프로그래밍: 함수형 프로그래밍에서는 상태 변이를 피하는 것이 중요한데, 불변 객체는 이러한 프로그래밍 패러다임에 맞는 데이터 구조이다.
정리
불변 객체는 동시성 문제를 해결하고 코드의 안정성을 높이는 데 중요한 역할을 한다. 자바에서 불변 객체를 만드는 방법은 비교적 간단하며, final 필드와 방어적 복사를 활용하면 쉽게 구현할 수 있다. 멀티스레드 환경이나 값 객체를 다룰 때 불변 객체를 사용하는 것은 매우 좋은 선택이다. 불변 객체의 올바른 사용을 통해 더 안전하고 효율적인 코드를 작성할 수 있다.
'Java' 카테고리의 다른 글
결제 동시성 이슈 해결 - 분산락과 Redisson (1) | 2024.10.03 |
---|---|
[Java] 버전 별 Map 선언 방법 (1) | 2024.09.27 |
[Java] 자바에서 Optional의 올바른 사용법 (0) | 2024.09.24 |
[Java] 공통 적용 JsonDeserializer 만들어 보기 (4) | 2024.09.23 |
[Java] UUID를 이용한 고유 식별자 생성 (1) | 2024.09.22 |
댓글