2018年4月24日火曜日

[JavaSE8 Goldへの道] その12 コレクションフレームワークに追加されたdefaultメソッド

JavaSE8 Goldへの道(Upgrade to Java SE 8 Programmer 1Z0-810 試験対策)12回目です。

一連の記事は「JavaSE8Gold」ラベルを付けていきます。

インタフェースのdefaultメソッドがどういうものかついてはその3で触れていますが、今回は実際に追加されたものをご紹介していきます。


Mapに追加されたメソッド

getOrDefault

default V getOrDefault(Object key, V defaultValue)

Map<String, String> map = new HashMap<>();
map.getOrDefault("key", "default");

キーにマッピングが存在しない場合、第2引数の値を返します。
「もし戻り値がnullだったら・・・」みたいなことをやらずに済みます。
本当は前回のOptionalが使えればよかったでしょうが、そうすると型が変わってコンパイルし直しになってしまうので仕方ないですね。


putIfAbsent

default V putIfAbsent(K key, V value)

Map<String, String> map = new HashMap<>();
map.putIfAbsent("key", "value");

通常のMap#putと引数が同じですが、キーにマッピングがないときだけ追加します。
Map#containsKeyと二段階の操作が1回で済みます。


compute

default V compute(K key,
                  BiFunction<? super K,? super V,? extends V> remappingFunction)

Map<String, String> map = new HashMap<>();
String msg = "default";
map.compute("key", (k, v) -> v == null ? msg : msg + v);

キーと現在の値に対して、新しい値を計算するラムダ式を渡します。
まだマッピングが存在しない場合はラムダ式の第二引数にnullが渡されます。

ややこしいですが、これも複数の手順を1回で済ませられます。
例えばキーの出現回数をカウントするといった状況は、ループの中はこのメソッド1行で済みます。

ラムダ式がnullを返した場合、マッピングは削除されます。


computeIfAbsent

default V computeIfAbsent(K key,
                          Function<? super K,? extends V> mappingFunction)

Map<String, List<String>> map = new HashMap<>();
List<String> list = map.computeIfAbsent("key", k -> new ArrayList<>());
キーに対するマッピングが存在しない場合のみ、ラムダ式を実行して値を格納します。

初めて現れた時だけコンテナを生成したいというとき、putIfAbsentだとラムダ式ではないので無駄にオブジェクトが生成されてしまいます。
そういうときはこちらを使えば無駄がありません。

おまけにマッピングされていたらその値を、されていなかったらラムダ式で生成した値を返します。

APIドキュメントには「もっとも一般的な用途は、次のように初期のマップされた値またはメモ化された結果として機能する新しいオブジェクトを構築することです。」と書いてありますが、そのへんの話はきしださんのページにわかりやすく書いてあります。
とても便利!

ラムダ式がnullを返した場合、マッピングが削除されるのは同じです。


computeIfPresent

default V computeIfPresent(K key,
                           BiFunction<? super K,? super V,? extends V> remappingFunction)

Map<String, String> map = new HashMap<>();
map.computeIfPresent("key", (k,v) -> v + "+");

今度は逆にマッピングされているときだけラムダ式を呼び出し、値を置き換えます。

Mapを作る時ではなく、一度作ったMap内のペアに対して何かの別の処理をさせたいと言うときなんかに使えそうです。
こちらも戻り値として生成した値を返します。
ラムダ式がnullを返した場合、マッピングが削除されるのは同じです。


marge

default V merge(K key,
                V value,
                BiFunction<? super V,? super V,? extends V> remappingFunction)

map.merge(key, msg, String::concat);
上のを全部合わせたような感じです。
keyに対するマッピングが存在しない場合はvalueを格納、存在する場合remappingFunctionを呼び出して返された値を格納します。

例えばString#concatで同じキーの値を全部連結するなどが1行で書けます。

ラムダ式がnullを返した場合、マッピングが削除されるのは同じです。


forEach

default void forEach(BiConsumer<? super K,? super V> action)

map.forEach((k,v) -> System.out.println(k + v));
説明は不要でしょう。
Map#entrySetからforループしてやる必要がなくなります。



Collection

removeIf

default boolean removeIf(Predicate<? super E> filter)
コレクション内の要素について、ラムダ式の条件を満たすものを*全て*削除します。

CollectionListなどの多数のインタフェースのスーパーインタフェースなので、いろんなクラスで使えます。

他に、何度も登場してきたstreamparallelStreamメソッドもJava8で追加されたdefaultメソッドです。


List

replaceAll

default void replaceAll(UnaryOperator<E> operator)

List<String> list = new ArrayList<>();
  :
list.replaceAll(s -> s + "!");

リストの全要素に対して、ラムダ式の結果で置き換えます。
ラムダ式には元の要素が順次渡されます。



Iterable

forEach

default void forEach(Consumer<? super T> action)

「リストにforEachなかったっけ?」と思った方。
Collectionよりさらに親のjava.lang.Iterableに実装されています。

IterableはJava5で拡張for文を導入するときに追加されました。
java.util.Iteratorとは違うので注意です。



と、い、う、わ、け、で

ストリームAPIがよくわからんという方は、まずこの辺から入ってラムダ式に慣れていくといいかもしれません。

今回も以下のサイトとGoldの通常試験の参考書を参考にしています。
一連の記事は「JavaSE8Gold」ラベルを付けていきます。

それではみなさまよきガジェットライフを(´∀`)ノ


0 件のコメント :
コメントを投稿

▼こちらの記事もどうぞ

▼ブログを気に入っていただけたらRSS登録をお願いします!
▼ブログランキング参加中!応援よろしくお願いします。

スポンサーリンク