LoginSignup
8
12

More than 5 years have passed since last update.

声に出して読みたい Java ライブラリ -UnmodifiableCollection-

Posted at

はじめに

Java では final の配列の要素は可変です。私が何を言っているかわからない方は下記のコードを実行してみてください。

finalのArrayは不変じゃない
public class Main {

    private static final String[] STRINGS = {"Tomato", "Orange", "Apple"};

    public static void main(final String[] args) {
        STRINGS[2] = "Cabbage";
        System.out.println(Arrays.toString(STRINGS));
    }
}

上記のコードを実行した際の出力は下記の通りです。

結果
[Tomato, Orange, Cabbage]

大変です! Apple が Cabbage に置き換わってしまいました。

では、固定の要素集合を提供するには?

『Effective Java』(日本語版第2版p70)にも書いてある通り、「変更できない要素の集合」を定義したいなら下記の方法を使いましょう。

Collections#unmodifiableList

引数で渡された List と同じ要素を持つ、変更不可の List を返すメソッドです。下記の例では Arrays#asList で一時的な List を作り、それを引数にして Collections#unmodifiableList を呼び出し、変更不可の List を取得しています。

private static final List<String> STRINGS
    = Collections.unmodifiableList(Arrays.asList("Tomato", "Orange", "Apple"));

実装はこちらのリンクをご参照ください。

ちなみに、Arrays#asList で生成される List は add と remove ができませんが、 set は可能です。

UnmodifiableCollection のよくないところ

ここから本題です。せっかく unmodifiableList を取得しても、Listの実装である以上は要素変更のメソッド(add/remove/set)が存在していますので、下記のコードは正常にコンパイル可能です。

STRINGS.set(2, "Cabbage");

が、実行すると下記の通り UnsupportedOperationException となります。

怒りのUnsupportedOperationException
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableList.set(Unknown Source)
    at jp.toastkid.Main.main(Main.java:13)

うーん……継承を使って実装する以上は仕方ないという感じですかね……しかし、実行時に例外を出されてプログラムを止められるよりは、コーディング中にコンパイルエラーを出してくれた方がいいと私は思います。

そこで

可能なら Eclipse Collections の ImmutableCollection を使ってみるとよいでしょう。元から add/remove/set が実装されていないので、間違って実行する以前にコンパイルエラーとなります。

下記の例では3つの要素を持つ ImmutableList のインスタンスを生成します。そのインスタンスに対し set メソッドを呼び出そうとしますが、そのようなメソッドは ImmutableList には実装されていないため、コンパイルが通りません。

ImmutableListの使用例
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.impl.factory.Lists;

......

    private static final ImmutableList<String> STRINGS 
        = Lists.immutable.of("Tomato", "Orange", "Apple");

    public static void main(final String[] args) {
        STRINGS.set(2, "Cabbage"); // ここでコンパイルエラー
        System.out.println(STRINGS);
    }

変更不可の状態を保てなくはなりますが、toList() メソッドで java.util.List への変換も可能です。

参考

  1. java.util.Collections
  2. java.util.Arrays
  3. org.eclipse.collections.api.collection.ImmutableCollection
  4. GS Collections 使い方メモ……GS Collections は Eclipse Collections の旧称です。
8
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12