안녕하세요. 개발자 Jindory입니다.
오늘은 Mutable Object와 Immutable Object에 대해서 알아보고자 합니다.
# 글 작성 이유
String과 StringBuffer를 비교할 때 Mutable한 특성과 Immutable한 특정이 언급되어 Mutable Object와 Immutable Object에 대한 특징에 대해서 알아보고자 합니다.
Mutable Objec와 Immutable Object란?
Mutable이란?
- 변하기 쉬운이라는 의미
- 프로그래밍에서는 한번 생성된 이후로 변할 수 있는것을 의미
- 상태가 자주 변경돼야하는 상황에서 필요(반복문 혹은 Collection)
- 이미 존재하는 객체에 재할당
- Multi-Thread 환경에서 문제가 발생할 수 있음
- arrays, ArrayList, HaspMap, 사용자가 생성한 Class 등등.....
Immutable이란?
- 불변이라는 의미
- 프로그래밍에서는 한번 생성된 이후로 변할 수 없는것을 의미
- 객체의 상태가 일정하게 유지되는지 보장 되어야 할 때(Muti-thread 환경)
- 이미 존재하는 객체라고 하더라도 새로운 객체를 생성하여 재할당
- Multi-Thread 환경에서 문제 없음
- Integer, Boolean, String과 같은 Wrapper class
Mutable Object와 Immutable Object가 Java에서 중요한 이유
Mutable Object를 사용하면 자주 변경해야하는 값에 대해서 편리하게 사용할 수 있으며, 복잡한 작업을 수행하는 소스코드에서 해당 객체가 어떻게 변경되는지 추적이 가능하다.
그러나 객체가 자주 수정되는 만큼 버그나 이슈가 발생하기 쉽고, 기존의 객체와 동일한 객체를 생성해야할 때 Mutable Object가 Immutable Object보다 효율성이 떨어지기 때문입니다.
이렇듯 Mutable Object와 Immutable Object의 특성을 이해하지 못 한 상태로 잘못 사용하면 예상치 못한 문제가 발생 할 수 있으므로, 버그없는 효율적인 코드 작성을 위해서는 반드시 둘의 특성을 이해하고 사용해야 합니다.
Mutable 그리고 Immutable Object의 장단점
- Mutable Objects
- 장점
- 상태 변경을 허용하므로, 동적 상황에서 유연하고 적응적으로 사용할 수 있습니다.
- 대량의 데이터의 경우 상태가 수정될 때, 새로운 객체를 생성하지 않아도 되므로 Immutable object에 비해 효율적 입니다.
- 특정 상황에서 메모리를 줄이고 효율적인 성능으로 상태를 수정할 수 있습니다.
- 단점
- Thread로부터 안전하지 않으며, 동시성 프로그래밍의 경우 사용에 있어서 주의가 필요합니다.
- 의도적이지 않은 변경이 발생했을 때, immutable object에 비해 덜 안전합니다.
- 많은 코드가 작성되었을때, 디버깅과 추론하기 어려울 수 있습니다.
- 장점
- Immutable Objects
- 장점
- 동기화 설정 없이 Multi-Thread 환경에서 안전하게 사용할 수 있습니다.
- 의도적이지 않은 변경이 발생했을 때, mutable object에 비해 안전합니다.
- 디버깅시 원인을 더 쉽게 추론이 가능합니다.
- 단점
- Mutable object에 비해 유연성이 떨어집니다.
- 많은 데이터를 다룰때, 객체 생성 후 상태가 변경되어야 하는 경우 덜 효율적일 수 있습니다.
- 상태 변경시 Mutable object에 비해 많은 메모리가 필요합니다.
- 장점
올바른 Immutable Object를 생성하는 방법
- 클래스를 final로 선언 : 클래스를 final로 선언하면, 다른 사람들이 클래스를 자유롭게 확장하거나 기능을 오버라이드 하거나 가변 속성을 추리하거나, 하위 클래스를 대체제로 제공하는것을 방지할 수 있습니다.
- 모든 field를 private로 만들기 : 모든 filed를 private로 만들면 한번 초기화 후 직접적으로 수정되는것을 방지할 수 있습니다.
- 모든 properties에 대해 setter 메서드 제공하지 않기 : setter를 제공하지 않으면, private인 properties에 직접적인 수정도 setter를 통한 수정도 불가능하게 됩니다.
- Defensive Copy : 원본객체의 상태를 변경하지 않고, 객체의 상태를 복사하여 새로운 객체를 생성하는 복사를 의미합니다.
- 생성자 초기화 보장 : 처음에 객체를 초기화 할 때, 모든 properties가 정의되고 생성되도록 생성자를 설계하며 setter나 다른 method에 의해 변경되는것을 피해야합니다.
올바른 Mutable Object를 생성하는 방법
- Class 선언 : 사용자가 원하는 Class 생성합니다.
- Properties 선언 : final이 아닌 properties를 선언합니다.
- Setter와 Getter method 생성 : 객체가 생성된 이후에도 값이 수정될 수 있도록 getter와 setter method를 제공합니다.
- 값을 변경할 수 있는 method 구현 : 필요시 properties의 값을 변경할 수 있는 method를 구현합니다.
- Multi-Thread 환경에서 thread-safety 하도록 보장 : synchronize를 추가하거나 Multi-Thread 환경에서 객체가 안전 할 수 있도록 구현 필요합니다.
- Object test : Test를 통해 객체 수정시 예측되는 방향으로 수정되는지, 쉽게 수정이 가능한지 검증이 필요합니다.
Java 프로그래밍에서 Mutable Object와 Immutable Object의 최선의 활용법
만일 Object을 생성 후 변경할 필요가 없다면 가능한 Mutable Object와 Immutable Object 중 Immutable한 Object를 선택하는것이 좋습니다. 이렇게 하면 개체의 상태가 간소화 되고 Thread가 동시에 수정하는 상황으로 인한 버그 및 경합 상태의 위험이 줄어듭니다.
아래는 Mutable Object와 Immutable Object를 사용할때 최선의 방법에 대해서 몇가지 정리한 내용입니다.
- Mutable한 상태를 최소화 한다 : Object를 변경할 수 있어야 하는 경우 Object에 포함된 변경 가능한 상태의 양을 최소화합니다. 이렇게 하면 Object의 동작에 대해 더 쉽게 추론할 수 있으며, 의도하지 않은 상태 변경으로 인한 버그의 위험을 줄일 수 있습니다.
- Defensive copying 사용 : Mutable한 Object를 method나 Class로 전달할 때, Original Object의 주소를 전달하는것 대신에 defensive copy를 사용하여 새로운 Object를 생성 후 복사하여 전달합니다. 이것은 Original 객체에 예상치 못한 변경이 일어나지 않도록 보장합니다.
- 공유되는 Mutable 상태에 대해서 동기적 접근처리 : 만일 다수의 thread의 접근이 필요하고, 동일한 Mutable 상태를 수정할 경우, 상태에 대한 액세스를 동기화하여 경합 상태 및 기타 동시성 문제를 방지합니다.
- 공용 인터페이스에서 Mutable한 상태를 노출 방지 : Object를 변경 가능한 상태가 포함된 경우 공용 인터페이스에 노출하지 말아야 합니다. 대신 캡슐화를 사용하여 상태를 숨기고 메서드 및 기타 인터페이스를 통해 제어된 액세스를 제공합니다.
- 신중한 테스트 및 디버그 : 변경 가능한 Object로 작업할 경우 신중하게 테스트하고, 디버깅하여 Object의 상태가 올바른지, 상태 변화는 어떤 방식으로든 의도하지 않은 부작용이 발생하지 않는지 확인이 필요합니다.
Mutable Object와 Immutable Object의 실생활 적용 사례
다음은 실생활에서 Java Appliation안의 Mutable한 Object와 Immutable한 Object에 대한 예시입니다.
- Date and Time : Java의 기본 라이브러리에, java.time 패키지에는 Mutable한 type과 Immutable한 type의 날짜와 시간을 나타내는 class가 포함되어 있습니다. LocalDateTime 클래스는 Mutable한 속성으로 언제든지 Setter를 통해 수정이 가능합니다. 반면 LocalDate는 Immutable한 Type으로 생성자를 통해서만 생성됩니다.
- Banking System : 은행 시스템은 금융 거래를 나타내기 위해 불변 객체를 사용하는것이 일반적입니다. 이는 교환의 기록이 정확성과 보안을 보장하기 위해 트랜잭션이 생성되며 수정해서는 안 되기 때문입니다.
- 게임 응용 Application : 게임 Application에서는 종종 위치 및 상태를 나타내는 객체를 mutable type으로 사용합니다. 이를 통해 게임이 진행됨에 따라 게임 상태를 실시간으로 업데이트 할 수 있습니다.
- 캐싱 시스템 : 캐싱 시스템에서 변경 가능한 객체는 주기적으로 업데이트 될 수 있는 캐시된 데이터를 저장하는데 사용할 수 있습니다. 예를 들어, 사용자 정보의 캐시는 사용자 프로파일에 대한 변경 사항을 반영하기 위해 주기적으로 업데이트되는 변경 가능한 객체에 저장될 수 있습니다.
- 데이터베이스 응용 프로그램 : 데이터베이스 응용 프로그램에서 변경할 수 없는 개체를 사용하여 응용 프로그램 코드에서 직접 수정해서는 안 되는 데이터 베이스 레코드를 나타낼 수 있습니다. 이렇게 하면 의도하지 않은 수정을 방지하여 데이터 베이스의 무결성과 보안을 보장할 수 있습니다.
결론
Mutable한 Type은 생성 후 변경이 자주 일어날때 유용하며, Immutable Type은 생성 후 변경되지 않는 상태를 보장할 때 유용합니다.전반적으로 Java에서 변경 가능한 객체와 변경할 수 없는 객체 중에서 선택하는 것은 어플리케이션의 특정 요구사항에 따라 다릅니다. 두 유형 모두 장단점이 있으며, 차이점을 이해하고 각 상황에 적합한 유형을 선택하는것이 중요합니다.
이렇게 mutable Object와 Immutable Object에 대해서 알아봤습니다.
혹시라도 정정할 내용이나 추가적으로 필요하신 정보가 있다면 댓글 남겨주시면 감사하겠습니다.
오늘도 Jindory 블로그에 방문해주셔서 감사합니다.
[ 참조 ]
Mutable and Immutable Objects in Java | DataTrained | Data Trained Blogs
'개발 > Java' 카테고리의 다른 글
[Java] Java Garbage Collection 동작 과정 (0) | 2023.12.16 |
---|---|
[Java] Java에서 Thread Unsafe한 상황 이해하기 (0) | 2023.12.15 |
[JAVA] static에 관하여 (0) | 2023.12.13 |
[JAVA] JVM 메모리 구조 (0) | 2023.12.13 |
[Java] 컴퓨터가 실수를 표현하는 방법과 실수 연산시 주의사항(IEEE 754) (0) | 2023.12.12 |