連載
» 2014年05月20日 18時00分 公開

Java 8はラムダ式でここまで変わる(4):Stream APIの主なメソッドと処理結果のOptionalクラスの使い方 (3/4)

[長谷川智之,株式会社ビーブレイクシステムズ]

最終的な処理を行うメソッド

 次に、集計結果を返したり要素を使って処理を実行したりする最終的な処理を行うメソッドを見てみましょう。Streamのメソッドの中で結果を返すものの中に処理結果を格納した「Optional」というクラスを返すものがあります。

 まずは、その戻り値となるOptionalについて見ていきましょう。

結果として使われるOptional

編集部注:一部内容の補足について(2014年7月28日)

本稿のOptionalクラスの使い方について一部読者から指摘があり、内容を補足させていただきました。


 Optionalとは値を格納するクラスです。主な使い方としてはStream APIの最終的なメソッドの処理結果としてOptionalが返されます。

 そして、Optional#getメソッドを使って格納された値を受け取ります。このとき、Optionalの値がない場合は例外が発生します。値があるかどうか確認するにはOptional#isPresentメソッドを使って確認します。Optional#isPresentメソッドの戻り値がtrueの場合は値があると判断できます。以下、Optionalの主なメソッドです。

戻り値 メソッド 概要
T get() Optional<T>で格納している値を返す。格納している値がない場合はNoSuchElementExceptionの例外が発生
boolean isPresent() 値が格納されている場合はtrue、格納されていない場合はfalseを返す
T orElse(T other) 値が格納されている場合はその値を返し、格納されていない場合は引数のotherを返す
T orElseGet(Supplier<? extends T> supplier) 値が格納されている場合はその値を返し、格納されていない場合はsupplierが生成した値を返す
T orElseThrow(Supplier<? extends Throwable> supplier) 値が格納されている場合はその値を返し、格納されていない場合はsupplierが発生させる例外を生成する
Optional<T> of(T value) Optionalのstaticなメソッド。引数のvalueを格納したOptionalを返す。引数のvalueはnullでないものしか設定しないようにする。valueがnullの場合、Optional#getメソッドで値を取得する際に例外が発生
Optional<T> ofNullable(T value) Optionalのstaticなメソッド。引数のvalueがnullでない場合、そのvalueを格納したOptionalを返す。nullの場合はOptional#emptyメソッドで生成されるOptionalを返す
Optional<T> empty() Optionalのstaticなメソッド。値が格納されていないOptionalを返す
void ifPresent(Consumer<? super T> consumer) Optionalが値を格納している場合はconsumerの処理を実行し、OptionalがEmptyの場合は何もしない
Optional<U> map(Function<? super T, ? super U> function Optionalが持つTの型を持つ値からfunctionによりUの型を持つ値を生成し、そのUの型の値を持つOptionalを返す
Optional<T> filter(Predicate<? super T> predicate) Optionalがpredicateによる判定でtrueの場合、Optionalに何も変化はなく、判定がfalseの場合、OptionalはEmptyになります。
// String"あ"を格納したOptionalから、その値を取得しています
System.out.println("Optional.of(\"あ\").get()=" + Optional.of("あ").get());
 
// Optionalに値が存在する場合はTrueを返します
System.out.println("Optional.of(\"あ\").isPresent()=" + Optional.of("あ").isPresent());
System.out.println("Optional.empty().isPresent()=" + Optional.empty().isPresent());
 
// Optionalに値があればその値を、なければorElseで指定した値を返します
System.out.println("Optional.of(\"あ\").orElse(\"い\")=" + Optional.of("あ").orElse("い"));
System.out.println("Optional.empty().orElse(\"い\")=" + Optional.empty().orElse("い"));
 
// Optionalに値があればその値を、なければSupplierが生成した値を返します
System.out.println("Optional.of(\"あ\").orElseGet(()->\"う\")=" + Optional.of("あ").orElseGet(()->"う"));
System.out.println("Optional.empty().orElseGet(()->\"う\")=" + Optional.empty().orElseGet(()->"う"));
 
// Optionalに値がなければ指定した例外をThrowします
try{
    Optional.empty().orElseThrow(()->new Exception("自作の例外"));
}
catch (Exception e){
    System.out.println(e);
}
// 引数の値がNullでなければその値を格納したOptionalを、NullならemptyなOptionalを返します
System.out.println("Optional.ofNullable(\"あ\")=" + Optional.ofNullable("あ"));
System.out.println("Optional.ofNullable(null)=" + Optional.ofNullable(null));
 
// Optionalに値がある場合、ifPresentの処理が実行されます
System.out.println("ifPresentの例(値がある場合):");
Optional.of("あ").ifPresent(value -> System.out.println("value=" + value));
 
// Optionalの値がEmptyの場合、ifPresentの処理は実行されません
System.out.println("ifPresentの例(値がない場合):");
Optional.empty().ifPresent(value -> System.out.println("value=" + value));
System.out.println("何も実行されません");
 
// Optionalの値から別の値を生成したOptionalを返します。
System.out.println("Optional<BigDecimal> bigDecimalOptional = Optional.of(\"12345\").map(value -> new BigDecimal(value))");
Optional<String> stringOptional = Optional.of("12345");
Optional<BigDecimal> bigDecimalOptional = stringOptional.map(value -> new BigDecimal(value));
BigDecimal result = bigDecimalOptional.get();
System.out.println("BigDecimal result = bigDecimalOptional.get()");
System.out.println("result=" + result);
System.out.println("result.getClass()=" + result.getClass());
 
// filterの結果がTrueの場合はそのままのOptionalを返します
System.out.println("Optional.of(new BigDecimal(\"1\")).filter(value -> value.compareTo(BigDecimal.ZERO) > 0)=" + Optional.of(new BigDecimal("1")).filter(value -> value.compareTo(BigDecimal.ZERO) > 0));
// filterの結果がFalseの場合はEmptyなOptionalを返します
System.out.println("Optional.of(new BigDecimal(\"1\")).filter(value -> value.compareTo(BigDecimal.TEN) > 0)=" + Optional.of(new BigDecimal("1")).filter(value -> value.compareTo(BigDecimal.TEN) > 0));
サンプル
Optional.of("あ").get()=あ
Optional.of("あ").isPresent()=true
Optional.empty().isPresent()=false
Optional.of("あ").orElse("い")=あ
Optional.empty().orElse("い")=い
Optional.of("あ").orElseGet(()->"う")=あ
Optional.empty().orElseGet(()->"う")=う
java.lang.Exception: 自作の例外
Optional.ofNullable("あ")=Optional[あ]
Optional.ofNullable(null)=Optional.empty
ifPresentの例(値がある場合):
value=あ
ifPresentの例(値がない場合):
何も実行されません
Optional<BigDecimal> bigDecimalOptional = Optional.of("12345").map(value -> new BigDecimal(value))
BigDecimal result = bigDecimalOptional.get()
result=12345
result.getClass()=class java.math.BigDecimal
Optional.of(new BigDecimal("1")).filter(value -> value.compareTo(BigDecimal.ZERO) > 0)=Optional[1]
Optional.of(new BigDecimal("1")).filter(value -> value.compareTo(BigDecimal.TEN) > 0)=Optional.empty
実行結果

 またOptionalもStreamと同様にプリミティブ型の数値を要素として扱うためのものが用意されています。次のものが拡張されたOptionalです。

Optionalの種類 概要
OptionalInt int値を格納するOptional
OptionalLong long値を格納するOptional
OptionalDouble double値を格納するOptional

Streamの中から特定の要素を取得するメソッド

 次はStreamが持つ要素を取得するメソッドを見てみましょう。以下は主なものです。

戻り値 メソッド 概要
Optional<T> max(Comparator<? super T> comparator) 要素の中で最大のものを返す。大小の比較には引数のcomparatorを使う。要素がなかった場合はemptyなOptionalを返す
Optional<T> min(Comparator<? super T> comparator) 要素の中で最小のものを返す。大小の比較には引数のcomparatorを使う。要素がなかった場合はemptyなOptionalを返す
Optional<T> findFirst() 要素の中で最初の要素を返す。要素がなかった場合はemptyなOptionalを返す
Optional<T> findAny() 要素の中の1つの要素を返す。要素がなかった場合はemptyなOptionalを返す
List<BigDecimal> list = new ArrayList<>();
list.add(new BigDecimal(3));
list.add(new BigDecimal(4));
list.add(new BigDecimal(5));
list.add(new BigDecimal(1));
list.add(new BigDecimal(2));
// 最大値の取得
Optional<BigDecimal> max = list.stream().max((a, b) -> a.compareTo(b));
System.out.println("max: " + max);
// 最小値の取得
Optional<BigDecimal> min = list.stream().min((a, b) -> a.compareTo(b));
System.out.println("min: " + min);
// 要素の最初のものを取得
Optional<BigDecimal> first = list.stream().findFirst();
System.out.println("first: " + first);
// 要素の中のどれか1つを取得
Optional<BigDecimal> any = list.stream().findAny();
System.out.println("any: " + any);
サンプル
max: Optional[5]
min: Optional[1]
first: Optional[3]
any: Optional[3]
実行結果

各要素を使った処理を行うメソッド

 次はStreamの各要素を受け取り、それを使って処理をするメソッドを見てみましょう。主なものは次のものになります。

戻り値 メソッド 概要
void forEach(Consumer<? super T> consumer) Streamの各要素をconsumerが引数として受け取り、処理を行う。並列処理で使った場合、元データがListのような集合体でも順番を保障しない
void forEachOrdered(Consumer<? super T> consumer) Streamの各要素が順番を担保している場合、その各要素をconsumerが順番通り引数として受け取り、処理を行う

 forEachの例は他のサンプルでも既に使っているので、ここでは並列処理の場合で見てみましょう。並列処理の場合、forEachメソッドは順番が保障されませんがforEachOrdedメソッドの場合はlistの順番が保たれます。

List<String> list = Arrays.asList(new String[]{"あ", "い", "う", "え", "お"});
Stream<String> parallelStream1 = list.parallelStream();
parallelStream1.forEach(value -> System.out.println("forEach: " + value));
Stream<String> parallelStream2 = list.parallelStream();
parallelStream2.forEachOrdered(value -> System.out.println("forEachOrdered: " + value));
サンプル
forEach: う
forEach: あ
forEach: え
forEach: い
forEach: お
forEachOrdered: あ
forEachOrdered: い
forEachOrdered: う
forEachOrdered: え
forEachOrdered: お
実行結果

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。