불변 객체(Immutable Object)

곽동현·2022년 10월 29일

JAVA

목록 보기
5/6
post-thumbnail

Clean code적으로나 java 언어를 공부하면서 클래스와 필드, 메소드는 불변성을 유지해야 한다는 문구를 많이 접했었다. 그 상태가 변하지 않게 한다.라는 뜻을 개발 측면에서 정확히 그 의도를 파악하기 위해 불변성의 의도와 올바른 사용법을 알고자 한다.

불변성 -> 객체

인스턴스가 생성된 이후 그 상태가 변하지 않는다.
클래스나 변수, 메소드에 불변성을 주기 위해서는 final 키워드를 사용한다.

final변수에 사용되면 값을 변경할 수 없는 상수가 되며
메서드에 사용되면 오버라이딩(overriding)을 할 수 없게 된다.
클래스에 사용되면 자신을 확장하는 자식 클래스를 정의하지 못하게 된다.


불변 객체 정의 과정

변수 선언 시 앞에 final을 붙여보자. 기본적으로 final은 초기화 후에 값을 변경할 수 없다.

  • 꼭 선언 시 초기화(명시적 초기화)를 해야 하나?
    : 그렇지는 않다. if문이나 생성자로 초기화가 가능하다. if문으로 조건 별로 초기화를 다르게 할 수 있다. 그러나 한 번 초기화시 다른 값으로 설정하는 것은 불가능하다.
class Test {
final String text;

boolean status = true;

if(status) { // final 변수 초기화
  	text = "hello";
  } else {
  		text = "bello~";
  }
  
  Test() { //final 변수 초기화 
  	text = "hello";
    }
}
  
  • static final 변수 또한 일반적인 final 변수와 동일한 특징을 가진다. 혹여 명시적 초기화를 하지 않는 경우에서는 static{} 안에서 초기화가 가능하다.
static final String text;

static {
	text = "hello";
}

  • 참조에 의해 값이 변경될 수 있는 점들을 유의해야 한다.
    : final은 초기화 이후 값 변경이 발생하지 않는다고 했다. 그러나 내부의 객체 상태를 변경하지 못하도록 하는 것은 아니다.
final List<String> list = new ArrayList<>(); // 불변 변수 list는 변경 불가
list.add("Hello");
list.add("bello");
... // 그러나 list 내부 변수는 변경이 가능하여 추가가 가능한 것

불변 객체를 생성하기 위해서는 다음과 같은 규칙에 따라서 클래스를 생성해야 한다.

  • 클래스final로 선언하라
  • 모든 클래스 변수privatefinal로 선언하라
  • 객체를 생성하기 위한 생성자 또는 정적 팩토리 메소드를 추가하라

정리

불변성을 줘서 얻을 수 있는 장점은 다음과 같다.

  • Thread-Safe하여 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 된다.
  • 실패 원자적인(Failure Atomic) 메소드를 만들 수 있다.
  • Cache나 Map 또는 Set 등의 요소로 활용하기에 더욱 적합하다.
  • 부수 효과(Side Effect)를 피해 오류가능성을 최소화할 수 있다.
  • 다른 사람이 작성한 함수를 예측가능하며 안전하게 사용할 수 있다.
  • 가비지 컬렉션의 성능을 높일 수 있다.

결국 불변성을 유지해야 하는 이유는 변경 가능성을 최소화하기 위함이라는 것을 알 수 있었다.


https://alexander96.tistory.com/16
https://mangkyu.tistory.com/131
https://7942yongdae.tistory.com/147

profile
읽고 쓰며 생각합니다 💡

1개의 댓글

comment-user-thumbnail
2023년 4월 7일

Q1. 왜 final 키워드를 붙이면 thread-safe 한가요?
Q2. 컬렉션의 불변을 지키기 위한 방법은 없나요?
Q3. 그렇다면 모든 변수에 final 키워드를 붙여야 하나요?
Q4. final 키워드의 단점은 없나요?

답글 달기