자바 불변 컬렉션


115

에서 자바 1.6 컬렉션 프레임 워크 문서 :

어떠한 수정 작업 (예를 지원하지 않는 컬렉션 add, removeclear)라고도 불가능한 . [...] Collection 객체의 변경 사항이 표시되지 않음을 추가로 보장하는 컬렉션을 불변 이라고합니다 .

두 번째 기준은 저를 약간 혼란스럽게합니다. 첫 번째 컬렉션을 수정할 수없고 원래 컬렉션 참조가 삭제되었다고 가정 할 때 두 번째 줄에서 참조되는 변경 사항은 무엇입니까? 컬렉션에 포함 된 요소의 변경, 즉 요소의 상태를 의미합니까?

두 번째 질문 :
컬렉션을 변경할 수없는 경우 지정된 추가 보증을 제공하는 방법은 무엇입니까? 컬렉션의 요소 상태가 스레드에 의해 업데이트되는 경우 해당 상태의 업데이트가 변경 불가능한 컬렉션을 보유하는 스레드에서 표시되지 않는 것으로 충분합니까?

컬렉션이 변경 불가능하도록하려면 지정된 추가 보장을 어떻게 제공합니까?


일반적으로 (특히 기능 언어에서) 불변 (일명 영속적) 컬렉션은이 컬렉션의 새로운 상태를 얻을 수 있다는 의미에서 변경 될 수 있지만 동시에 이전 상태는 다른 링크에서 계속 사용할 수 있습니다. 예를 들어 newCol = oldCol.add("element")는 1 개 이상의 요소가있는 이전 컬렉션의 복사 본인 새 컬렉션을 생성하고에 대한 모든 참조 oldCol는 여전히 변경되지 않은 동일한 이전 컬렉션을 가리 킵니다.
ffriend

답변:


154

수정할 수없는 컬렉션은 일반적으로 다른 컬렉션의 읽기 전용보기 (래퍼)입니다. 추가, 제거 또는 지울 수 없지만 기본 컬렉션은 변경 될 수 있습니다.

변경 불가능한 컬렉션은 전혀 변경할 수 없습니다. 다른 컬렉션을 래핑하지 않고 자체 요소를 가지고 있습니다.

다음은 구아바의 인용문입니다. ImmutableList

Collections.unmodifiableList(java.util.List<? extends T>)여전히 변경 될 수있는 별도의 컬렉션보기 인와 달리 의 인스턴스 ImmutableList는 자체 개인 데이터 를 포함하며 절대 변경되지 않습니다.

따라서 기본적으로 변경 가능한 컬렉션에서 변경할 수없는 컬렉션을 가져 오려면 해당 요소를 새 컬렉션에 복사하고 모든 작업을 허용하지 않아야합니다.


@Bhaskar-내 마지막 단락을 참조하십시오.
Bozho

1
다른 수정 불가능한 컬렉션 안에 래핑 된 컬렉션에 다른 참조가없는 경우 수정 불가능한 컬렉션의 bahaviour는 변경 불가능한 컬렉션과 정확히 동일합니까?
Bhaskar

1
@Bozho, 백업 컬렉션에 대한 참조가 제공되지 않고 수정 불가능한 컬렉션 래퍼 참조 만 제공되면 변경할 수있는 방법이 없습니다. 그럼 왜 "확신 할 수 없어"라고 말합니까? 백킹 컬렉션이 수정 가능하기 때문에 일부 스레드 또는 어떻게 든 수정되는 시나리오를 지적합니까?
AKS

@AKS : 컬렉션이 래핑 될 때 unmodifiableList해당 목록에 대한 참조 만받는 코드는 수정할 수 없지만 원래 목록에 대한 참조가 있고 래퍼가 생성되기 전에 수정할 수있는 코드는 계속됩니다. 나중에 그렇게 할 수 있습니다. 원래 목록을 만든 코드가 그 안에 존재했던 모든 참조에 무슨 일이 일어 났는지 알고 있고 목록을 수정할 수있는 코드의 손에 들어 가지 않을 것이라는 것을 알고 있다면 목록이 절대로 없을 것임을 알 수 있습니다. 수정되었습니다. 그러나 참조가 외부 코드에서 수신 된 경우 ...
supercat

... unmodifiableList랩핑 된 컬렉션이 어떻게 변경되는지 여부 또는 방법을 알 수있는 방법은 없습니다.
supercat dec

86

차이점은 변경을 허용하는 불변 컬렉션에 대한 참조를 가질 수 없다는 것입니다. 수정할 수없는 컬렉션은 해당 참조를 통해 수정할 수 없지만 일부 다른 개체는 변경할 수있는 동일한 데이터를 가리킬 수 있습니다.

예 :

List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);

1
원본 컬렉션 참조가 기본 컬렉션을 수정하는 데 사용되지 않는 경우 어떤 다양한 원인이 컬렉션에 수정 불가능한 변경을 가져올 수 있습니까?
Bhaskar

21
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1이다 변경 가능한 (즉,도 불가능한불변 ).
c2이다 불가능한 : 그 자체를 변경할 수 없습니다,하지만 난 변경할 나중에 경우 c1다음 것을 변경에 표시됩니다 c2.

이것은 c2단순히 래퍼 c1이며 실제로는 독립적 인 사본 이 아니기 때문 입니다 . Guava는 ImmutableList인터페이스 와 일부 구현을 제공합니다 . 그것들은 실제로 입력의 복사본을 만드는 방식으로 작동합니다 (입력이 자체적으로 변경 불가능한 컬렉션이 아닌 경우).

두 번째 질문에 대해 :

컬렉션 의 가변성 / 불변성은 그 안에 포함 된 객체의 가변성 / 불변성에 의존 하지 않습니다 . 컬렉션에 포함 된 개체를 수정하는 것은 이 설명에 대한 "컬렉션 수정"으로 간주 되지 않습니다 . 물론 변경 불가능한 컬렉션이 필요한 경우 일반적으로 변경 불가능한 객체도 포함하기를 원합니다.


2
@John : 아니요, 아닙니다. 적어도 OP에서 인용 한 정의에 따르지 않습니다.
Joachim Sauer

@JohnVint, 정말? 나는 그렇게 생각하지 않을 것입니다. c1을 사용하면 여전히 요소를 추가 할 수 있으며이 추가는 c2에서 볼 수 있습니다. 그것은 불변이 아니라는 것을 의미하지 않습니까?
Bhaskar

글쎄요, c1이 탈출 할 수 있다면 그것은 불변하지 않을 것이지만 불변성은 또한 컬렉션 내의 내용을 나타냅니다. 나는 더 많은 java.util.Date의의 unmodifiableCollection를 참조이었다
존 빈트

1
@Vint : "if c1does not escape"는 사양에서 구별되는 고려 사항이 아닙니다. 제 생각에는, 경우에 당신이 할 수 는 비 불변하게하는 방법으로 컬렉션을 사용하여, 당신은해야한다 항상 이 아닌 불변 고려하십시오.
Joachim Sauer 2011

1
정의를 인용하겠습니다 : "추가적으로 보장 하는 컬렉션 "(내 강조). Collection.unmodifiableList() 수없는 그것의 인수가 탈출하지 않음을 보장 할 수 없기 때문에, 그것을 보장합니다. Guava 는 인수가 이스케이프하더라도 ImmutableList.of 항상 immutable을 생성합니다 List.
Joachim Sauer

17

이제 Java 9 에는 Immutable List, Set, Map 및 Map.Entry에 대한 팩토리 메소드가 있습니다.

Java SE 8 및 이전 버전에서는 unmodifiableXXX와 같은 Collections 클래스 유틸리티 메서드를 사용하여 Immutable Collection 개체를 만들 수 있습니다.

그러나 이러한 Collections.unmodifiableXXX 메서드는 매우 지루하고 장황한 접근 방식입니다. 이러한 단점을 극복하기 위해 Oracle corp는 List, Set 및 Map 인터페이스에 몇 가지 유틸리티 메서드를 추가했습니다.

이제 Java 9에서 :-List 및 Set 인터페이스에는 아래와 같이 비어 있거나 비어 있지 않은 Immutable List 또는 Set 객체를 만드는 "of ()"메서드가 있습니다.

빈 목록 예

List immutableList = List.of();

비어 있지 않은 목록 예

List immutableList = List.of("one","two","three");

2
그리고 자바 10 List.copyOfSet.copyOf목록 / 세트의 변경 불가능한 사본을 만들 수 있도록하거나 이미 불가능한 경우 지정된 컬렉션을 반환하는 추가 된 참조 JDK - 8191517
Marcono1234

6

여기서 요점은 컬렉션이 수정할 수없는 경우에도 변경할 수 없다는 것을 보장하지 않는다는 것입니다. 예를 들어 너무 오래된 요소를 제거하는 컬렉션을 생각해보십시오. 수정할 수 없음은 참조를 보유한 객체가 변경할 수 없음을 의미하는 것이 아니라 변경할 수 없음을 의미합니다. 이것의 진정한 예는 Collections.unmodifiableList방법입니다. 수정 불가능한 List 뷰를 반환합니다. 이 메서드에 전달 된 List 참조는 여전히 수정 가능하므로 전달 된 참조의 모든 소유자가 목록을 수정할 수 있습니다. 이로 인해 ConcurrentModificationExceptions 및 기타 나쁜 일이 발생할 수 있습니다.

불변이란 컬렉션을 변경할 수 없음을 의미합니다.

두 번째 질문 : 변경 불가능한 컬렉션은 컬렉션에 포함 된 개체가 변경되지 않는다는 의미가 아니라 해당 컬렉션이 보유하는 개체의 수와 구성이 변경되지 않을 것입니다. 즉, 컬렉션의 참조 목록은 변경되지 않습니다. 그렇다고 참조되는 개체의 내부가 변경 될 수 없다는 의미는 아닙니다.


잘 했어 !! 따라서 Unmodifiable Collection에 대한 래퍼를 만들고 수정 가능한 컬렉션 참조를 비공개로 설정하면 변경 불가능하다는 것을 확신 할 수 있습니다. 권리?
AKS

내가 당신의 질문을 이해한다면 대답은 아니오입니다. Unmodifiable을 래핑하면 컬렉션이 unmodifiableList수정되도록 전달되지 않도록 보호 할 수 없습니다 . 이 작업을 수행하려면 ImmutableList.
John B

0

Pure4J 는 두 가지 방법으로 당신이 추구 하는 것을 지원합니다.

첫째, @ImmutableValue주석을 제공 하므로 클래스에 주석을 달아 변경 불가능하다고 말할 수 있습니다. 코드가 실제로 변경 불가능한지 (사용 final등) 확인할 수있는 maven 플러그인이 있습니다 .

둘째, Clojure의 영구 컬렉션 (제네릭이 추가됨)을 제공하고 컬렉션에 추가 된 요소가 변경되지 않도록합니다. 이것들의 성능은 분명히 꽤 좋습니다. 컬렉션은 모두 변경할 수 없지만 검사를 위해 Java 컬렉션 인터페이스 (및 제네릭)를 구현합니다. Mutation은 새 컬렉션을 반환합니다.

면책 조항 : 나는 이것의 개발자입니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.