[자바] final 키워드 & 불변 객체
References
📌 final 키워드
- final 키워드: 한 번만 할당 가능하다는 선언
- 재할당하려고 하면 컴파일 오류가 발생해 바로 확인이 가능
- 왜 final 키워드를 사용해야 할까?
- 실수로 값을 재할당해 로직이 꼬여 장애가 발생할 수 있다
- 좋은 코드는 제약을 두어 의도를 드러내야 한다
- 마치 기본 생성자를 protected, private 으로 설정해 사용하지 못하게 막는것 처럼
- 개발은 혼자 하는게 아님. 다른 사람이 객체의 값을 변경하거나, 로직에서 파라미터 값을 임의로 재할당해 장애를 일으킬 수 있다
- 불변을 유지하려고 만들면 객체지향적인 코드가 나오기도 한다
- final 적용 효과
- 서비스 안정성이 높아짐(버그 발생 가능성이 줄어든다, 코드 품질이 높아진다)
📌 불변 객체(Immutable Object)
- 한 번 생성되면 내부의 상태를 변경(추가, 제거, 수정)할 수 없는 객체
- 상태를 변경할 수 없다? 이는 Heap 메모리 영역에서 객체가 가리키고 있는 데이터 자체의 변화가 불가능하다는 것을 의미
- 불변 객체는 read-only 메서드만을 제공, 객체의 내부 상태를 제공하는 메서드를 제공하지 않거나 방어적 복사(defensive-copy)를 통해 제공
- 대표적으로 Java의 String 클래스가 불변 객체
- 방어적 복사: 참조를 통해 값을 전달하지 않고 내부를 복사해 전달
- 불변 객체는 신뢰할 수 있다
public class Money {
private final long money;
private Money(final long money) {
this.money = money;
}
public static Money of(final long money) {
return new Money(money);
}
}
불변 객체의 장점
- 멀티 스레드 동기화 문제 방지
- 불변 객체를 사용해라 성능상의 단점은 미미하다. 현대 컴퓨터의 성능을 무시하지 마라 - 제이슨
- 불변 객체는 간단하고 신뢰성 있는 코드를 만들기 위한 전략이다 - 오라클 자바 튜토리얼
- 불변 객체는 가변 객체보다 설계하고 구현하고 사용하기 쉬우며, 오류도 생길 여지도 적고 훨씬 안전하다 - 이펙티브 자바
- 클래스들은 가변적이여야 하는 매우 타당한 이유가 있지 않는 한 반드시 불변으로 만들어야 한다. 만약 클래스를 불변으로 만드는 것이 불가능하다면, 가능한 변경 가능성을 최소화하라. - 이펙티브 자바
📌 불변 객체와 final을 사용해야 하는 이유
아직 성능적인 요소를 고려할 단계는 아니다. 불변 객체가 오류를 줄이고 오용을 막는다는 장점에 먼저 집중하자
- 사이드 이펙트를 줄여 오류가능성을 최소화
- 다른 사람이 객체, 메서드, 클래스를 사용할 때 오용을 막을 수 있다
- GC의 성능을 높일 수 있다
- Thread-safe해 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 된다
📌 불변객체를 만드는 방법
Java는 불변성을 제공하기 위해 final 키워드를 제공하고 있다. 변수에 final 키워드를 붙이면 참조값을 변경하지 못하게 만들어 불변성을 확보할 수 있다
- 클래스를 final로 선언한다
- 모든 클래스 변수를 private final로 선언한다
- setter를 사용하지 않고 생성자를 사용한다
- 참조에 의해 변경가능성을 막기 위해 방어적 복사와 깊은 복사를 이용한다
primitive type 불변객체 생성
- setter를 생성하지 않는다
- 생성자 주입, 정적 팩토리 메서드로만 필드값을 설정한다
참조 타입(reference type) 불변객체 생성
- 생성자를 통해 값을 전달받을 때 new ArrayList<>(cars)를 통해 새로운 값을 참조하도록 복사(방어적 복사)
- getter에서는 Collections의 unmodifiableList() 메서드를 이용해 반환
public class Cars {
private final List<Car> cars;
public Cars(List<Car> cars) {
this.cars = new ArrayList<>(cars);
}
public List<Car> getCars() {
return Collections.unmodifiableList(cars);
}
}
댓글남기기