読者です 読者をやめる 読者になる 読者になる

kagamihogeの日記

kagamihogeの日記です。

JDK 9 Early Access ReleasesでCollections Convenience Factories initialを試す

環境

説明

概要

java.util.Listインタフェースなどに、引数に要素を指定してイミュータブルなコレクションを生成するためのファクトリーメソッドが追加されている。これにより、少数の固定要素でコレクションを生成するのが容易となっている。

実行例は以下の通り。なお、コードの試行例はJDK 9で追加予定のREPLを用いている。

-> List.of("a", "b", "c", "d", "d")
|  Expression value is: [a, b, c, d, d]
|    assigned to temporary variable $30 of type List<String>

-> $30
|  Variable $30 of type List<String> has value [a, b, c, d, d]

List.of(...)という形でListのインスタンス生成が出来ていることがわかる。

List

java.util.ListインタフェースにイミュータブルなListを返すstaticなファクトリーメソッドが追加されている。以下、javadocから抜粋。

static <E> List<E>    of()
static <E> List<E>     of(E... elements)
static <E> List<E>     of(E e1)
static <E> List<E>     of(E e1, E e2)
//中略
static <E> List<E>     of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

要素が10個まではその数に対応する個数の引数を持つ専用のメソッドが定義されている。これはJEP 269によると、個数が小さくかつ固定の場合は最適化の余地があるため、とされている。

他に、空リストを返すものと、引数が10個以上の場合は可変長引数で受け取るメソッドが用意されている。

実際に使ってみる。

-> List.of()
|  Expression value is: []
|    assigned to temporary variable $26 of type List<Object>

-> List.of(1,2,3,4,5)
|  Expression value is: [1, 2, 3, 4, 5]
|    assigned to temporary variable $27 of type List<Integer>

-> List.of(1,2,3,4,5,6,7,8,9,10,11,12,13)
|  Expression value is: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|    assigned to temporary variable $28 of type List<Integer>

-> List.of(1,null)
|  java.lang.NullPointerException thrown
|        at Objects.requireNonNull (Objects.java:220)
|        at List.of (List.java:803)
|        at (#39:1)

->

イミュータブルなリストを作るためのメソッドなので、引数にnullを指定すると実行時例外となる。

Set

java.util.Setインタフェースにも同様なメソッドが追加されている。

static <E> Set<E>     of()
static <E> Set<E>  of(E... elements)
static <E> Set<E>  of(E e1)
static <E> Set<E>  of(E e1, E e2)
//中略
static <E> Set<E>  of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

実際に使ってみる。

-> Set.of(1,1)
|  java.lang.IllegalArgumentException thrown: duplicate elements
|        at Set.of (Set.java:482)
|        at (#43:1)

-> Set.of()
|  Expression value is: []
|    assigned to temporary variable $34 of type Set<Object>

-> Set.of(1)
|  Expression value is: [1]
|    assigned to temporary variable $35 of type Set<Integer>

-> Set.of(9,4,2,6,3,1,7,8,0)
|  Expression value is: [0, 1, 2, 3, 4, 6, 7, 8, 9]
|    assigned to temporary variable $36 of type Set<Integer>

-> $36
|  Variable $36 of type Set<Integer> has value [0, 1, 2, 3, 4, 6, 7, 8, 9]

Setなので重複要素が入れられない以外はListと変わらない。

Map

java.util.Mapインタフェースにも同様なメソッドが追加されているが、引数にkey-valueの組み合わせを指定する関係で若干使い勝手が異なる。以下のように、引数の順序が、1つ目のkey, 1つ目のvalue, 2つ目のkey, 2つ目のvalue... となっている。

-> Map.of("key1","value1", "key2", "value2")
|  Expression value is: {key1=value1, key2=value2}
|    assigned to temporary variable $39 of type Map<String,String>

javadocからの抜粋は以下の通り。

static <K,V> Map<K,V>     of()
static <K,V> Map<K,V>  of(K k1, V v1)
static <K,V> Map<K,V>  of(K k1, V v1, K k2, V v2)
(中略)
static <K,V> Map<K,V>  of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)
static <K,V> Map.Entry<K,V>    entry(K k, V v)
static <K,V> Map<K,V>  ofEntries(Map.Entry<? extends K,? extends V>... entries)

ListやSetと異なり、Mapはkey-valueの組が必要なので、可変長引数で任意の要素を受け取るメソッドが無い。その代わりに、ofEntriesというMap.Entryを可変長引数で受け取るメソッドが追加されている。

実際に使ってみる。

-> Map.ofEntries(
>>     Map.entry("key111", "value111"),
>>     Map.entry("key222", "value222"))
|  Expression value is: {key222=value222, key111=value111}
|    assigned to temporary variable $43 of type Map<String,String>

-> import static java.util.Map.entry

-> Map.ofEntries(
>>     entry("key111", "value111"),
>>     entry("key222", "value222"))
|  Expression value is: {key222=value222, key111=value111}
|    assigned to temporary variable $45 of type Map<String,String>

さすがにちょっと記述が冗長な感じになるのは否めないが、個人的には許容範囲内ではある。JEPにも記述があるのだが、固定個数のMapを作りたいケースの要素数はせいぜい8個までだろう、と書かれている。なので、staticインポートでMap.entyrentryにする悪あがきで、まぁ十分なんじゃないっすかね。

参考文献