概要
Java8 Stream APIを使用したサンプルコードです。
サンプルコード
streamインスタンス
streamインスタンスを取得するサンプルコードです。
java.util.stream.Stream#of
Stream<String> stream = Stream.of("A","B","C","D","E");
java.util.Arrays#stream
Stream<String> stream = Arrays.stream(new String[]{"A","B","C","D","E"});
java.util.Collection#stream
List<String> list = Arrays.asList("A","B","C","D","E");
Stream<String> stream = list.stream();
java.lang.CharSequence#chars
String str = "ABCDE";
IntStream streamf = str.chars();
Stream#forEach
理解を助けるために同じ処理について関数インターフェースを実装する方法、ラムダ式を使う方法、メソッド参照を使う方法で記述しました。
関数インターフェースを実装する例
Stream<String> streamf = Arrays.stream(new String[]{"A","B","C","D","E"});
streamf.forEach(new Consumer<String>() {
@Override
public void accept(String name) {
System.out.println(name);
}
});
ラムダ式で実装する例
streaml.forEach((final String name) -> System.out.println(name));
ラムダ式は状況によってコードを簡略化することができます。
上記のコードはコンパイラの型推論によって、下記のように引数の型情報を省略することができます。
streaml.forEach((name) -> System.out.println(name));
さらに引数が1つの場合は丸カッコを省略することができます。
streaml.forEach(name -> System.out.println(name));
メソッド参照で実装する例
さらにコード全体をメソッド参照に置き換えることができます。
streaml.forEach(System.out::println);
Stream#forEach (その2)
文字列のコレクションを加工した結果を別のコレクションへ保存するサンプルコードです。
forEachメソッドの戻り値はありませんので、処理結果を受け取りたい場合はメソッドの外で定義した変数を使用します。
関数インターフェースを実装する例
Stream<String> streamf = Stream.of("A","B","C","D","E");
final List<String> resultf = new ArrayList<>();
streamf
.forEach(new Consumer<String>() {
@Override
public void accept(final String name) {
String tmp = name.toLowerCase();
System.out.println(tmp);
resultf.add(tmp);
}
});
System.out.println(resultf);
// ⇒ [a, b, c, d, e]
ラムダ式で実装する例
Stream<String> streaml = Stream.of("A","B","C","D","E");
final List<String> resultl = new ArrayList<>();
streaml
.forEach(name -> {
String tmp = name.toLowerCase();
System.out.println(tmp);
resultl.add(tmp);
});
System.out.println(resultl);
// ⇒ [a, b, c, d, e]
Stream#map, Stream#collect
文字列のコレクションを加工した結果を別のコレクションへ保存するサンプルコードです。
上記のforEachメソッドを使った例と処理内容は同じですが、外部の変数を必要としない点で副作用がありません。
関数インターフェースを実装する例
collectメソッドの
- 第1引数のSupplierは、処理結果を格納する型(コンテナ)のインスタンスを生成する処理を記述します。
- 第2引数のBiConsumerは、Supplierで生成したインスタンスへ処理結果を格納する処理を記述します。
- 第3引数のBiConsumerは、処理結果を格納したインスタンスを他のインスタンスにまとめる処理を記述します。
Stream<String> streamf = Arrays.stream(new String[]{"A","B","C","D","E"});
final List<String> resultf =
streamf
.map(new Function<String, String>() {
@Override
public String apply(final String s) {
return s.toLowerCase();
}
})
.collect(
new Supplier<List<String>>() {
@Override
public List<String> get() {
return new ArrayList<String>();
}},
new BiConsumer<List<String>, String>() {
@Override
public void accept(final List<String> t, final String s) {
t.add(s);
}
},
new BiConsumer<List<String>, List<String>>() {
@Override
public void accept(final List<String> t, final List<String> u) {
t.addAll(u);
}
}
);
System.out.println(resultf);
// ⇒ [a, b, c, d, e]
ラムダ式で実装する例
Stream<String> streaml1 = Arrays.stream(new String[]{"A","B","C","D","E"});
final List<String> resultl1 =
streaml1
.map(s -> s.toLowerCase())
.collect(
() -> new ArrayList<String>(),
(t, s) -> t.add(s),
(t, u) -> t.addAll(u)
);
System.out.println(resultl1);
// ⇒ [a, b, c, d, e]
メソッド参照で実装する例
(注) ArrayList::newはコンストラクタ参照です。
Stream<String> streaml2 = Arrays.stream(new String[]{"A","B","C","D","E"});
final List<String> resultl2 =
streaml2
.map(String::toLowerCase)
.collect(ArrayList<String>::new, ArrayList<String>::add, ArrayList<String>::addAll);
System.out.println(resultl2);
// ⇒ [a, b, c, d, e]
CollectorsクラスのtoListメソッドで下記のように書き換えることができます。
ちなみにtoListの他にもtoMapやtoSetなどがあります。
Stream<String> streaml3 = Arrays.stream(new String[]{"A","B","C","D","E"});
final List<String> resultl3 =
streaml3
.map(String::toLowerCase)
.collect(Collectors.toList());
System.out.println(resultl3);
// ⇒ [a, b, c, d, e]
他の例になりますが、Collectors#joiningで文字列の結合処理を簡単に記述できます。
Stream<String> streaml = Arrays.stream(new String[]{"A","B","C","D","E"});
String resultl =
streaml
.map(String::toLowerCase)
.collect(Collectors.joining(",","[","]"));
System.out.println(resultl);
// ⇒ [a,b,c,d,e]
Stream#filter, Stream#reduce
数値のコレクションから条件に一致するデータの合計を得るサンプルコードです。
関数インターフェースを実装する例
List<Integer> list = Arrays.asList(30, 110, -30, 70, 20, -10, 60);
Stream<Integer> streamf = list.stream();
Integer sumf =
streamf
.filter(new Predicate<Integer>() {
@Override
public boolean test(final Integer t) {
return t >= 0;
}
})
.reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(final Integer t, final Integer u) {
return t + u;
}
})
.get();
System.out.println(sumf);
// ⇒ 290
ラムダ式で実装する例
List<Integer> list = Arrays.asList(30, 110, -30, 70, 20, -10, 60);
Stream<Integer> streaml = list.stream();
Integer suml =
streaml
.filter(t -> t >= 0)
.reduce((t,u) -> t + u)
.get();
System.out.println(suml);
// ⇒ 290
Stream#distinct
コレクションから重複するデータを除いたコレクションを生成するサンプルコードです。
ラムダ式で実装する例
Stream<String> stream = Arrays.stream(new String[]{"A","a","B", "B", "b", "C", "D", "DD", "E"});
final List<String> result =
stream
.map(s -> s.toLowerCase())
.filter(s -> s.length() == 1)
.distinct()
.collect(Collectors.toList());
System.out.println(result);
// ⇒ [a, b, c, d, e]
Stream#flatMap
複数のstreamを1つに束ねて処理するサンプルコードです。
関数インターフェースで実装する例
List<List<String>> list = new ArrayList<>();
List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
List<String> list2 = Arrays.asList("a", "b", "c", "d", "e");
List<String> list3 = Arrays.asList("あ", "い", "う", "え", "お");
list.add(list1);
list.add(list2);
list.add(list3);
Stream<String> streamf =
list.stream().flatMap(new Function<List<String>, Stream<? extends String>>() {
@Override
public Stream<? extends String> apply(List<String> t) {
return t.stream();
}
});
List<String> resultf = streamf.collect(Collectors.toList());
System.out.println(resultf);
// ⇒ [A, B, C, D, E, a, b, c, d, e, あ, い, う, え, お]
ラムダ式で実装する例
List<List<String>> list = new ArrayList<>();
List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
List<String> list2 = Arrays.asList("a", "b", "c", "d", "e");
List<String> list3 = Arrays.asList("あ", "い", "う", "え", "お");
list.add(list1);
list.add(list2);
list.add(list3);
Stream<String> streaml =
list.stream().flatMap(l -> l.stream());
List<String> resultl = streaml.collect(Collectors.toList());
System.out.println(resultl);
// ⇒ [A, B, C, D, E, a, b, c, d, e, あ, い, う, え, お]
Stream#flatMap (その2)
関数インターフェースで実装する例
Map<Integer, List<String>> map = new HashMap<>();
List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
List<String> list2 = Arrays.asList("a", "b", "c", "d", "e");
List<String> list3 = Arrays.asList("あ", "い", "う", "え", "お");
map.put(1, list1);
map.put(2, list2);
map.put(3, list3);
Stream<Entry<Integer, List<String>>> stream1 = map.entrySet().stream();
Stream<String> streamf =
stream1.flatMap(new Function<Entry<Integer, List<String>>, Stream<? extends String>>() {
@Override
public Stream<? extends String> apply(Entry<Integer, List<String>> t) {
return t.getValue().stream();
}
});
List<String> resultf = streamf.collect(Collectors.toList());
System.out.println(resultf);
// ⇒ [A, B, C, D, E, a, b, c, d, e, あ, い, う, え, お]
ラムダ式で実装する例
Map<Integer, List<String>> map = new HashMap<>();
List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
List<String> list2 = Arrays.asList("a", "b", "c", "d", "e");
List<String> list3 = Arrays.asList("あ", "い", "う", "え", "お");
map.put(1, list1);
map.put(2, list2);
map.put(3, list3);
Stream<Entry<Integer, List<String>>> stream2 = map.entrySet().stream();
Stream<String> streaml =
stream2.flatMap(m -> m.getValue().stream());
List<String> resultl = streaml.collect(Collectors.toList());
System.out.println(resultl);
// ⇒ [A, B, C, D, E, a, b, c, d, e, あ, い, う, え, お]
リファレンスメモ
java.util.stream
[package] (http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)
[Interface Stream] (http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)
[Class Collectors] (http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html)
java.lang
[Interface Iterable] (https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)
java.util
[Class Arrays] (https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html)
[Interface Collection] (https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html)
java.util.function
[package] (http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html)
[Interface Supplier<T>] (http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html)
T get()
[Interface Predicate<T>] (https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html)
boolean test(T t)
[Interface Consumer<T>] (http://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html)
Type Parameters:
T - the type of the input to the operation
void accept(T t)
[Interface Function<T,R>] (http://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html)
Type Parameters:
T - the type of the input to the function
R - the type of the result of the function
R apply(T t)