Java 8のStream API入門


Java 8のStream APIについての紹介です。Stream APIではラムダ式を使うのでラムダ式を合わせて説明します。


ラムダ式(Lambda)

Javaのラムダ式(Lambda)は、クロージャ(Closure)とも呼ばれています。ラムダ式は「関数型インターフェイス」の実装で使います。

@FunctionalInterface
public interface IntFunc {
public abstract void func(int x);
}
IntFunc intFunc1 = new IntFunc() {
@Override
public int func(int x) {
return x + x;
}
}

ラムダ式を使うと上のインターフェイスを次のように書き直すことができます。

IntFunc intFunc2 = (int x) -> { return x + x; };

Stream API

Java 8で導入された機能で、配列やCollectionなどの集合体の値の集計などに便利なAPIです。Stream<t>といったインターフェイスで要素を処理します。

Stream APIには「中間操作」と「終端操作」が存在します。

中間操作を行う主なメソッドは次のようなものがあります。

🗻 条件を満たす要素のみ選別:filter

filterメソッドは、Predicateで定義したbooleanの判定がtrueの要素のみに絞ったStreamを返します。

Integer[] array = { 1, 2, 3, 4, 5, 6, 7 };
Arrays.stream(array)
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer val) {
return val % 3 == 0;
}
})
.forEach(System.out::println);
// 3
// 6

上記と同じことを省略形で書くと次のようになります。

Integer[] array = { 1, 2, 3, 4, 5, 6, 7 };
Arrays.stream(array)
.filter(val -> val % 3 == 0)
.forEach(System.out::println);
// 3
// 6

👽 各要素に特定の処理を行う:map

mapメソッドは、各要素に対して指定した処理を行いその結果のStreamを返します。

Integer[] array = { 1, 2, 3 };
Arrays.stream(array)
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer val) {
return val * 3;
}
})
.forEach(System.out::println);

上記と同じことを省略形で書くと次のようになります。

Integer[] array = { 1, 2, 3 };
Arrays.stream(array)
.map(val -> val * 3)
.forEach(System.out::println);
// 3
// 6
// 9

🎳 指定した個数の要素を返す:limit

limitメソッドはmaxSize個の要素のStreamを返します。

Integer[] array = { 1, 2, 3, 4, 5, 6, 7 };
Arrays.stream(array)
.limit(3)
.forEach(System.out::println);
// 1
// 2
// 3

🐝 重複のない要素を返す:distinct

distinctメソッドはmaxSize個の要素のStreamを返します。

Integer[] array = { 1, 2, 1, 2, 1, 2 };
Arrays.stream(array)
.distinct()
.forEach(System.out::println);
// 1
// 2

🚌 指定した並び順に並べ直す:sorted

sortedメソッドは、Comparatorで比較し並べ替えたStreamを返します。

List<Integer> list = Arrays.asList(3, 2, 1);
list.stream()
.sorted()
.forEach(System.out::println);
// 1
// 2
// 3

🎃 集合に対する操作:collect

collectメソッドはArrayやList等のデータ構造を変化するのに使います。

List<Integer> list = Arrays.asList(3, 2, 1);
List<Integer> result = list.stream()
.sorted()
.collect(Collectors.toList());
result.stream().forEach(System.out::println);

Collectorsで文字列の連結:joining

Collectorsのメソッドで文字列の連結に使うのがjoiningメソッドです。

System.out.println(Stream.of("A", "B", "C")
.collect(Collectors.joining("-"))); //=> A-B-C
System.out.println(Stream.of("A", "B", "C")
.collect(Collectors.joining("-", "[", "]"))); //=> [A-B-C]

🐮 ひとつでもマッチすればtrueを返す:anyMatch

anyMatchメソッドは要素の中でどれかひとつでも条件にマッチすればtrueを返します。

List<String> list = Arrays.asList("Tokyo", "Osaka", "Nagoya");
System.out.println(list.stream().anyMatch(val -> val.length() == 6)); //=> true
System.out.println(list.stream().anyMatch(val -> val.length() == 7)); //=> false

🗽 すべて一致すればtrueを返す:allMatch

allMatchメソッドはすべての要素が条件を満たせばtrueを返します。

List<String> list = Arrays.asList("Tokyo", "Osaka", "Nagoya");
System.out.println(list.stream().allMatch(val -> val.length() >= 5)); //=> true
System.out.println(list.stream().allMatch(val -> val.length() >= 6)); //=> false

🏀 すべてマッチしなければtrueを返す:noneMatch

noneMatchメソッドはすべての要素が条件を満たさない、ひとつもマッチしない場合にtrueを返します

List<String> list = Arrays.asList("Tokyo", "Osaka", "Nagoya");
System.out.println(list.stream().noneMatch(val -> val.length() >= 7)); //=> true
System.out.println(list.stream().noneMatch(val -> val.length() >= 6)); //=> false

🐠 参考リンク

📚 おすすめの書籍

🖥 サーバについて

このブログでは「Cloud Garage」さんのDev Assist Program(開発者向けインスタンス無償提供制度)でお借りしたサーバで技術検証しています。 Dev Assist Programは、開発者や開発コミュニティ、スタートアップ企業の方が1GBメモリのインスタンス3台を1年間無料で借りれる心強い制度です!(有償でも1,480円/月と格安)