Java

Immutable object, 불변객체

leeheefull 2022. 4. 17. 00:44

불변 객체란?

 

불변 객체란 재할당은 가능하지만, 이미 할당된 내부 데이터를 변경시킬 수 없는 것을 말합니다. 쉽게 말해서, 한 번 만들면 수정이 불가하고 수정하고 싶다면 다시 만들어야 합니다.

 

 

 

 

불변 객체의 예시

 

Java의 불변 객체의 대표적인 예로는 String이 있습니다. String.class를 둘러보면, 원시 타입의 필드 값인 value는 전부 생성자를 통해서 관리하고, 나머지 메서드는 Read Only만 가능합니다.

 

이 말이 뜻하는 것은 String은 한 번 할당하면 내부 데이터를 변경할 수 없고, 변경하고 싶다면 생성자를 통해서 재할당해야 한다는 것입니다. 즉, 불변 객체라는 말입니다.

 

https://user-images.githubusercontent.com/58816862/129442777-20b1d727-f78e-497d-a02e-9c1e86b385c4.png

 

 

평소에 String 값을 바꿀 때 변경하는 것처럼 보이지만, 사실은 아래처럼 변경하는 것이 아니라 재할당 해주는 것입니다.

 

https://user-images.githubusercontent.com/58816862/129441740-cff974cd-9926-487e-826b-f42d9f3129b5.png

 

 

 

 

불변 객체가 되기 위한 조건

 

불변 객체가 되기 위해서는 클래스 안의 필드 값들이 전부 final로 선언되어야 합니다. final로 선언된 필드는 Setter를 만들 수 없고 생성자를 통해서 값이 전달됩니다. 이를 기반으로 코드를 작성하면 아래와 같이 불변 객체가 완성됩니다.

 

https://user-images.githubusercontent.com/58816862/129443953-ace314b6-d19a-4787-bde8-2a5e70ba25e3.png

 

 

그렇다면, 아래와 같은 경우에 Member.class는 불변 객체라고 할 수 있을까요?

 

https://user-images.githubusercontent.com/58816862/129443570-0ad753ce-3558-40f2-bc8f-fabb7c947ae7.png

 

아닙니다. 위처럼 불변 객체의 필드가 참조 타입이라면 참조 객체의 필드 값들 또한 final로 선언되어야 합니다. 그렇지 않으면, 아래 코드처럼 Name.class를 통해서 결국 name은 수정이 가능합니다.

 

https://user-images.githubusercontent.com/58816862/129443730-575416a2-c980-4ba0-891c-ced24a2580b9.png

 

그렇다면, Member.class가 불변 객체가 되려면 어떻게 해야 할까요?

 

 

https://user-images.githubusercontent.com/58816862/129443585-48861249-f4ea-4ab2-a56a-9c25febb2e20.png

 

위처럼 Name.class가 불변 객체가 된다면, Member.class도 불변 객체라고 할 수 있습니다.

 

 

 

 

불변 객체를 사용하는 이유

 

Thread Safe

 

멀티 스레드 환경에서 동기화 문제의 발생 이유는 공유 자원을 동시에 사용하기 때문입니다. 근데 공유 자원이 불변 객체라면, 동기화를 고려하지 않아도 됩니다.

 

 

실패 원자적인(Failure Atomic) 메서 드를 만들 수 있다?

 

실패 원자적이란, 호출된 서비스가 실패하더라도 해당 객체는 메서드 호출 전으로 돌아가는 것을 말합니다. 불변 객체의 생성 시점에서 유효성 검사를 진행한다면, 이후에는 절대 변하지 않기 때문에 기존 객체가 불안정 상태에 빠지는 일이 없습니다.

 

 

Side effect 최소화

 

한 번 객체화시킨 변수에 대해서 다른 참조자를 가질 수 없기 때문에 Side Effect를 피해 오류 가능성을 최소화할 수 있습니다.

 

사이드 이팩트란 변수의 값이 변경되었을 때, 이러한 변화가 불러일으키는 영향을 의미합니다. 만약 객체의 Setter가 구현되어 있고, 여러 메서드에서 객체의 값이 변경된다면 객체를 예측하기 어려워질 것입니다.

 

객체의 바뀐 상태를 파악하기 위해서는 메서드들을 살펴보아야 할 것이며 이러한 부분은 유지보수성을 상당히 떨어뜨립니다. 불변 객체는 기본적으로 값의 수정이 불가능하기 때문에 변경 가능성이 적으며, 객체의 생성과 사용이 상당히 제한됩니다.

 

그렇기 때문에 메서드들은 자연스럽게 순수 함수들로 구성될 것이고, 다른 메서드가 호출되어도 객체의 상태가 유지되기 때문에 안전하게 객체를 다시 사용할 수 있습니다. 이러한 불변 객체는 오류를 줄여 유지보수성이 높은 코드를 작성하도록 도와줄 것입니다.

 

 

예측 가능한 코드

 

다른 사람이 작성한 함수를 예측 가능하며 안전하게 사용할 수 있습니다. 불변성은 협업을 하는 과정에서도 도움을 주는데, 불변성이 보장된 함수라면 다른 사람이 개발한 함수를 위험 없이 이용할 수 있습니다.

 

마찬가지로 다른 사람도 내가 작성한 메서드를 호출하여도, 값이 변하지 않음을 보장받을 수 있기 때문에 다른 사람의 코드를 변경하는 것에 대한 불안 없이 이용할 수 있습니다.

 

 

GC 성능 증가

 

가비지 컬렉션의 성능을 높일 수 있다. 불변의 객체를 활용하면 가비지 컬렉터가 스캔해야 되는 객체의 수가 줄어서 스캔해야 하는 메모리 영역과 빈도수 역시 줄어들 것이고, GC가 수행되어도 지연 시간을 줄일 수 있을 것입니다.

 

그렇기 때문에 필드 값을 수정할 수 있는 가변 객체보다 필드 값을 수정할 수 없는 불변 객체를 사용하는 것이 좋습니다.

 

 

 

 

단점

 

생성할 때 초기값이 아닌, 새로운 값을 입력하려면 새 객체를 만들어야 합니다. 그만큼 자원의 소모가 많아질 수밖에 없습니다. 그만큼 코드 재사용성이 떨어진다고 말할 수 있습니다.

 

 

 

이상입니다. 수정 사항이나 피드백이 있으시다면 편하게 댓글 부탁드리겠습니다. 글 읽어 주셔서 감사합니다