「終端操作」だけまとめる。

Streamの操作には「中間操作」と「終端操作」があり、
ここでは「終端操作」だけをまとめる。

一覧表にすると次のようになる。

分類 終端操作 概要
集める collect 集合にする
toArray 配列にする
副作用 forEach、forEachOrdered 副作用を起こさせる
数える count 件数を数える
集計 reduce リデュースする
条件判定 anyMatch allMatch noneMatch 条件を判定する
比較 max min 最大値・最小値を返す
取り出す findFirst findAny 要素を返す

必ずStreamオブジェクトを返す「中間操作」と異なり、
「終端操作」は戻り値が多岐にわたる。

collection array void boolean Optionalと
それぞれ違う。

「終端操作」は一度終端操作が終わったStreamに対しては
実行できないので注意する。

collect

<R,A> R collect(Collector<? super T,A,R> collector)

ストリームの要素を集合として出力(生成)する。

引数のcollectorについては、
基本的なものはCollectorsに用意されているので
それを利用する。

List<Integer> expected = Arrays.asList(1, 2, 3, 4);
 
Integer[] numbers = { 1, 2, 3, 4 };
List<Integer> actual = Arrays.stream(numbers).collect(Collectors.toList());
assertThat(actual, is(expected));

toArray

<A> A[] toArray(IntFunction<A[]> generator)

ストリームの要素を配列として出力(生成)する。

collectで集合は作成できるので
配列はこれで作れる。

引数に配列を生成するIntFunctionを
渡せばよい。

Integer[] expected = { 1, 2, 3, 4 };
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Integer[] actual = numbers.stream().toArray(Integer[]::new);
assertThat(actual, is(expected));

forEach、forEachOrdered

void forEach(Consumer<? super T> action)

終端操作として、副作用を発生させる場合に用いる。

以前(JavaSE7)のfor文の感覚からすると
forEachで全部作りたくなってしまうが
それはガマンしなくてはいけない。

それをやってしまうと処理をforEachに押し込んでいるだけなので
意味が伝わりにくく、並列化もしにくい。

中間操作の組合せを検討するべき。

List<Integer> expected = Arrays.asList(2, 3, 4);
 
List<AtomicInteger> numbers = Arrays.asList(new AtomicInteger(1), new AtomicInteger(2), new AtomicInteger(3));
Consumer<AtomicInteger> action = number -> number.incrementAndGet();
numbers.stream().forEach(action);
 
// 比較するために変換
List<Integer> actual = numbers.stream().map(AtomicInteger::intValue).collect(Collectors.toList());
assertThat(actual, is(expected));

count

long count()

ストリームの要素数を返す。

long expected = 4;
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
long actual = numbers.stream().count();
assertThat(actual, is(expected));

reduce

T reduce(T identity,BinaryOperator<T> accumulator)

map/reduceでおなじみのreduce。

計算結果が次の引数になるかたちで、
累積して処理(集計)することが可能なメソッド。

次のような処理が行われるイメージ。

T result = identity;
result = accumulator(result,element1);
result = accumulator(result,element2);
result = accumulator(result,element3);
return result;
Integer expected = 24;
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
 
BinaryOperator<Integer> accumulator = (a, b) -> a * b;
Integer actual = numbers.stream().reduce(1, accumulator);
assertThat(actual, is(expected));
                

anyMatch allMatch noneMatch

boolean anyMatch(Predicate<? super T> predicate)

predicate(条件)にどれだけマッチするか調べる。

結果がtrueになる条件は、
それぞれ次のようになる。

メソッド trueになる条件
anyMatch predicateの評価が1つでもtrueの場合
allMatch predicateの評価が全てtrueの場合
noneMatch predicateの評価が全てfalseの場合
boolean expected = true;
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Predicate<Integer> predicate = i -> i == 4;
boolean actual = numbers.stream().anyMatch(predicate);
assertThat(actual, is(expected));

max min

Optional<T> max(Comparator<? super T> comparator)

compareで比較した結果の最大値や最小値を返す。

結果はOptionalで返ってくるのが
JavaSE8っぽい。

Integer expected = 4;
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Optional<Integer> optional = numbers.stream().max(Integer::compare);
Integer actual = optional.orElse(null);
assertThat(actual, is(expected));

findFirst findAny

Optional<T> findFirst()

要素を取り出す。

maxと同様にOptionalで結果が返ってくる。

Integer expected = 1;
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Optional<Integer> optional = numbers.stream().findFirst();
Integer actual = optional.orElse(null);
assertThat(actual, is(expected));

PR