[Java] Immutable Object

불변 객체

불변(不辨) 객체란 생성 후에 바꿀 수 없는 객체를 말한다. 보통 불변 객체는 대게 생성 시에 결정되지만 경우에 따라 실제 사용 시점까지 늦추는 경우도 있다. 보통의 불변 객체는 객체를 복사하게 되면 객체 자체가 아닌 참조값을 복사만 하고 끝낸다. 즉, 객체를 복사할 때 같은 값을 가진 객체가 메모리에 하나 더 생성되는것이 아닌 참조만 리턴한다는 의미이다. 이렇게 객체 대신 참조를 복사하는 기법을 Intern 기법이라 한다.

In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object’s state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

Strings and other concrete objects are typically expressed as immutable objects to improve readability and runtime efficiency in object-oriented programming. Immutable objects are also useful because they are inherently thread-safe. Other benefits are that they are simpler to understand and reason about and offer higher security than mutable objects.

String은 대표적인 불변 객체이다. 이 때문에 String을 비교할 때에는 ==연산자를 사용해서는 안되는 이유이다.

불변객체 왜 필요한걸까

  1. 멀티 스레드 환경에서의 안전
  2. 방어적 복사본의 불필요
  3. 사이드 이펙트의 발생 확률 저하

단점도 존재한다.
객체가 가지는 값마다 새로운 객체가 필요하니 memory leak과 새로운 객체를 계속 생성해야하는 문제 때문에 성능 저하를 유발한다.

불변객체 만들기

Primitive Type

1
2
3
4
5
6
7
8
9
10
11
12
public class ImmutablePrimitiveObject {
//final로 선언한다
private final int value;

public ImmutablePrimitiveObject(final int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

Reference Type

일반 객체

참조 타입이 일반 객체인 경우 일반 객체도 불변으로 만들어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ImmutableReferenceTypeObject {
private final ImmutableReferenceType referenceType;

public ImmutableReferenceTypeObject(final ImmutableReferenceType referenceType) {
this.referenceType = referenceType;
}

public ImmutableReferenceType getReferenceType() {
return this.referenceType;
}
}

public class ImmutableReferenceType {
private final int value;

public ImmutableReferenceType(final int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

Array

참조 타입이 배열인 경우 배열을 불변으로 만들고 clone을 반환한다. 참조를 그대로 반환해서는 안된다. 또한 생성 시 참조를 그대로 받아 사용하면 안되고 복사해서 생성해야 한다.

1
2
3
4
5
6
7
8
9
10
11
public class ImmutableArrayObject {
private final int[] array;

public ImmutableArrayObject(final int[] array) {
this.array = Arrays.copyOf(array, array.length);
}

public int[] getArray() {
return (array == null) ? null : array.clone();
}
}

Collection

참조 타입이 콜렉션인 경우 생성시 참조를 그대로 사용해선 안되고 복사해야 하며 반환시 참조를 반환해서는 안된다. 혹은 콜렉션 자체를 불변으로 만든다.

1
2
3
4
5
6
7
8
9
10
11
public class ImmutableReferenceTypeObject {
private final ImmutableReferenceType referenceType;

public ImmutableReferenceTypeObject(final ImmutableReferenceType referenceType) {
this.integerList = Collections.unmodifiableList(new ArrayList<>(integerList));
}

public ImmutableReferenceType getReferenceType() {
return this.referenceType;
}
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/12/Languages/Java/immutableObject/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.