Unmodifiable – Java Puzzlers Advent Calendar3日目

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>(Arrays.asList("aaa", "bbb", "ccc"));
        List<String> unmodifiableList = Collections.unmodifiableList(strings);
 
        System.out.print(unmodifiableList.size());
        System.out.print(", ");
        strings.remove("aaa");
 
        System.out.print(unmodifiableList.size());
    }
}

上のコードを実行した時の結果はどれになるでしょうか?

  1. 3, 3
  2. 3, 2
  3. 実行時エラー
  4. コンパイルエラー

答え

2の3, 2が出力されます


解説

今回の問題はKotlinのListがImmutableではない!みたいな話を聞いたのを思い出して似たような問題を取り上げました。
Javadocを見るとCollections#unmodifiableListメソッドの解説にはこのように書かれています。

指定されたリストの変更不可能なビューを返します。

Collections#unmodifiableListは変更が不可能なListとしてラップするだけで防御的コピーはしていません。なので、元のリストを操作すれば変更可能なので注意してください。


解決策

不変なリストを作りたい場合は防御的コピーをするようにしてください。

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>(Arrays.asList("aaa", "bbb", "ccc"));
        //↓新しいリストを作る
        List<String> unmodifiableList = Collections.unmodifiableList(new ArrayList<>(strings));
 
        System.out.print(unmodifiableList.size());
        System.out.print(", ");
        strings.remove("aaa");
 
        System.out.print(unmodifiableList.size());
    }
}

もしくはUnsupportedOperationExceptionで死ぬのは嫌なのでEclipseCollectionsなどを使うのが良いかと思います。