상세 컨텐츠

본문 제목

ImmutableList에 대한 고찰

Spring/JAVA

by Chan.94 2024. 10. 13. 21:13

본문

반응형

왜 ImmutableList가 필요할까?

다른 개발자들과 협업하기 위해서는 '예측 가능한 코드를 작성해야 한다.'

 

우리는 다른 개발자가 작성한 코드를 사용하여 개발하고, 다른 개발자들은 다시 우리가 작성한 코드에 기반해서 자신의 코드를 작성한다. 이 과정에서 예상치 못한 Side Effect가 발생하게 된다.

ImmutableList를 사용하면 Side Effect를 줄일 수 있다.

 

ImmutableList는 함수를 호출하는 쪽에서 명확하게 알 수 있도록 할 수 있기 때문이다.


ImmutableList

Immutable의 사전적 의미로 불변의, 변경할 수 없는 이라는 뜻을 가지고 있다. 즉 추가, 삭제, 변경이 불가능한 List를 말하며 Collection이 생성된 후 변경되는 것을 방지할 때 사용할 수 있다.

 

ImmutableList를 변경하려고 할 경우 UnsupportedOperationException이 발생한다.

 

ImmutableList 구현방법

  • Collections.unmodifiableList()
    - Java 8
    - 기존 리스트를 불변 뷰로 감싸서 반환
    - 원본 리스트에 대한 참조를 유지하므로, 원본 리스트가 변경되면 반환된 불변 뷰도 영향을 받는다.

  • List.of()
    - Java 9
    - List, Set, Map 인터페이스에 Immutable Collection을 만들 수 있는 메서드 of가 추가됨

  • Google Guava 라이브러리의 ImmutableList
    - 생성된 리스트는 원본 리스트에 의존하지 않고, 이후에도 변하지 않는다.
    - 다양한 빌더 패턴과 팩토리 메서드 제공

Collections.unmodifiableList()와  ImmutableList 비교

  • Collections.unmodifiableList()
    • 원본 리스트를 감싸는(wrapper) 형태로 동작한다. 즉, 원본 리스트의 내용을 변경하면 unmodifiableList도 영향을 받는다.
      이는 완벽한 불변성이 아닌, 단지 수정 시도를 방지하는 읽기 전용 뷰(View)만 제공하는 방식이다.
    • 생성하는 과정에서는 비용이 거의 없다.
    • 원본 리스트와 참조 관계를 유지하므로 동기화가 필요한 경우가 생길 수 있다.
      원본 리스트가 변경될 수 있는 상황에서는 성능 및 안정성 문제가 발생할 수 있다.
  • ImmutableList (Google Guava)
    • 생성된 리스트는 원본 리스트에 의존하지 않고, 이후에도 변하지 않는다. (리스트가 복사됨)
    • 리스트 생성 시 약간의 추가 비용이 발생하지만, 생성 후에는 불변 리스트이므로 성능 최적화가 가능하다.
    • 스레드 안전성: 여러 스레드에서 동시에 접근해도 안전

Collections.unmodifiableList() Example

// 리스트 생성
List<String> originalList = new ArrayList<>();
originalList.add("Red");
originalList.add("Green");
originalList.add("Blue");

// 불변 리스트로 변환
List<String> unmodifiableList = Collections.unmodifiableList(originalList);

System.out.println("Original List: " + originalList);
System.out.println("Unmodifiable List: " + unmodifiableList);

// 원본 리스트를 변경하면 unmodifiableList에 영향이감
originalList.add("Yellow");

System.out.println("Original List: " + originalList);
System.out.println("Unmodifiable List: " + unmodifiableList);

// unmodifiableList 수정
// UnsupportedOperationException 발생
try {
    unmodifiableList.add("Purple");
} catch (UnsupportedOperationException e) {
    System.out.println("Cannot modify ImmutableList: " + e);
}

 

Output

Original List: [Red, Green, Blue]
Unmodifiable List: [Red, Green, Blue]
Original List: [Red, Green, Blue, Yellow]
Unmodifiable List: [Red, Green, Blue, Yellow]
Cannot modify ImmutableList: java.lang.UnsupportedOperationException

 


ImmutableList (Google Guava) Example

List<String> originalList = new ArrayList<>();
originalList.add("Red");
originalList.add("Green");
originalList.add("Blue");
System.out.println("originalList: " + originalList);

// of() 메서드 사용
ImmutableList<String> unmodifiableList1 = ImmutableList.of("Red", "Green", "Blue");
System.out.println("unmodifiableList1: " + unmodifiableList1);

// copyOf() 메서드 사용
ImmutableList<String> unmodifiableList2 = ImmutableList.copyOf(originalList);
System.out.println("unmodifiableList2: " + unmodifiableList2);

// 빌더 패턴 사용
ImmutableList<String> unmodifiableList3 = ImmutableList.<String>builder()
        .add("Red")
        .add("Green")
        .add("Blue")
        .build();
System.out.println("unmodifiableList3: " + unmodifiableList3);

// reverse() 메서드 사용
ImmutableList<String> reversedUnmodifiableList4 = unmodifiableList3.reverse();
System.out.println("reversedUnmodifiableList4: " + reversedUnmodifiableList4);

// 수정 시도
try {
    unmodifiableList2.add("Yellow");
} catch (UnsupportedOperationException e) {
    System.out.println("Cannot modify ImmutableList: " + e);
}

 

Output

originalList: [Red, Green, Blue]
unmodifiableList1: [Red, Green, Blue]
unmodifiableList2: [Red, Green, Blue]
unmodifiableList3: [Red, Green, Blue]
reversedUnmodifiableList4: [Blue, Green, Red]
Cannot modify ImmutableList: java.lang.UnsupportedOperationException
반응형

관련글 더보기

댓글 영역

>