Java でプログラムを書いていると,標準の java.util.Collection フレームワークを使うことが必須になるでしょうが,なるべくスマートに書こうよ,という趣旨.
第1弾として「初期化」と「変更不可能」について.それ以外は思い立ったら書きます.
Java 1.8, それと Guava, Apache Commons utils が使えるという状況を前提とします.
初期化
ナントカの一つ覚えのように Lists.newArrayList()
ばかり呼ばないこと.
標準のコンストラクタ
標準のコンストラクタ.ダイアモンド演算子を書かなければいけない (1.6 以前なら総称型の省略も不可能),初期化のパターンとしてやや乏しいので,余り使わない.
List<String> lines = new ArrayList<>();
List<String> another = new ArrayList<>(lines); // java.util.Colleciton を引数で受けられる
Guava の初期化
コレクションの実装毎に、初期データを突っ込みつつインスタンス構築する方法を何パターンか用意してくれているので,使いやすい。
実装毎に初期化メソッドがたくさんあるので,API ドキュメントを読んだことない人はぜひご一読を.
List<String> lines = Lists.newArrayList("石井琢朗", "波留敏夫", "鈴木尚典");
Guava の Immutable Collection
変更不可能なコレクションを作る.
List<String> twoPlans = ImmutableList.of("佐伯貴弘", "中根仁");
twoPlans.add("マラベ") // UnsupportedOperationException が投げられる
// Key-Value を繰り返す
Map<Integer, String> rotation = ImmutableMap.of(11, "斎藤隆", 16, "川村丈夫", 21, "野村弘樹", 18, "三浦大輔", 63, "戸叶尚");
Immutable Collection の Builder
上記の Immutable Collections には,それぞれ Builder がある。
Builder<String> builder = ImmutableList.builder();
builder.add("島田直也");
builder.add("阿波野秀幸", "五十嵐英樹", "横山道哉"); // 可変長引数で承けられる。
List<String> releivers = builder.build();
java.util.Collections の singleton
要素を変更出来ないようにする場合,Immutable Collection の他にも,単一要素しか持たないなら,これで初期化するのもあり。
List<String> bobby = Collections.singletonList("ローズ");
Map<Integer, String> basesLoaded = Collections.singletonMap(Integer.valueOf(10), "駒田徳広");
変更不可能
初期化とも被る範囲もあるが,コレクションの状態を変更させない (add/remove などを許容しない) ようにすると,余計なことに気を使わなくて良くなるので,その方法について.
特に public Set<String> getXXX()
みたいなメソッドの返す Collection は,変更不可能にしておいたほうが良いことが多い.(あくまで一般論)
java.util.Collections の unmodifiable
状態変更系のメソッドを呼ぶと UnsupportedOperationException
を投げるようにしてあるラッパー.Effective Java にも書いてあるが,あまり良くないケースもある.オリジナルのコレクションが変更されないことがわかっている,もしくは一時的に返す View である場合にのみ使う.
Collection<String> coaches = Lists.newArrayList("権藤博", "山下大輔", "高木由一");
Collection<String> view = Collections.unmodifiableCollection(coaches);
view.add("森祇晶"); // 状態を変更するメソッドなので,これは UnsupportedOperationException() がスローされる。
coaches.add("牛島和彦"); // これは出来る。
view.contains("牛島和彦"); // 変更しないメソッドについては,view は coaches に処理を移譲するだけなので,true が返ってくる.
Guava の Immutable Collection
こっちは,元のコレクションの要素を新しいコレクションにも詰めるようにしているので,その心配なし。
少し余談になるが,copyOf
というメソッド名は,「オリジナルのコピーを作ることでインスタンスを初期化するんだよ」ということを表している良いメソッド名であり,Static Factory Method のメリットを享受している良い例であると言える.(Effective Java の項目1を参照)
Collection<String> coaches = Lists.newArrayList("権藤博", "山下大輔", "高木由一");
// ラッパーではないので java.util.Collections の問題が起きない。
// コピーであることを示す、という意味で Static Factory Method のメリットも享受している。()
Collection<String> view = ImmutableList.copyOf(coaches);
「上記にはないけど,こんな書き方,よくしない?」というのあったら,ご指摘ください.