关于Java的Stream API

首先

这是一篇面向StreamAPI初学者的文章。
该文章不涉及StreamAPI中使用的Lambda表达式。(请参考这篇文章)

StreamAPI是什麼

StreamAPI是从Java SE8开始添加的一种功能,可以很好地处理集合的操作。基本上,它遵循以下步骤进行处理。

    1. 获取Stream

 

    1. 执行中间操作对Stream的元素进行操作

 

    执行终端操作获取结果

相关的类被整理在java.util.stream包中。

使用方法

流媒体的类别

主要的Stream对象包括以下内容。
通常的Stream只能处理引用类型的值,因此还专门提供了处理原始类型的Stream。

Stream扱う型Stream参照型IntStreamint型LongStreamlong型DoubleStreamdouble型

获取流的方法

可以通过以下模式获得Stream。

// ListからStreamを取得
List<String> list = List.of("twitter", "instagram", "facebook");
Stream<String> stream = list.stream();

// 配列からStreamを取得
String[] strArraly = {"twitter", "instagram", "facebook"};
Stream<String> stream = Stream.of(strArraly);

// プリミティブ型を扱うStreamを取得
IntStream stream = IntStream.of({1, 2, 3, 4, 5});

// Stream.of()だとInteger型を扱うStreamが取得される
Stream<Integer> stream = Stream.of({1, 2, 3, 4, 5});

// 要素数が無限
Stream<Integer> stream = Stream.generate(() -> new Random().nextInt());

对于”中間操作”,只需要一个中文翻译选项:

对Stream中的元素进行操作并返回一个新的Stream的操作。
可以通过使用方法链将返回新的Stream,来进行描述。

中间操作列表(部分)
メソッド内容引数filter条件に一致する要素のみのStreamを返すPredicatemap別の型を扱うStreamを返すFunctionmapToIntintStreamを返すFunctiondistinct要素の重複を排除したStreamを返す
※equalsメソッドでtrueを返すものなしlimit指定された要素数のStreamを返すintskip指定された数分の要素を飛ばしたStreamを返すintsorted引数で指定した順序に従ってソートされたStreamを返す
※引数なしの場合は自然順序に従うComparatorpeek現在の要素に対して関数を適用し、Streamを返すConsumer

使用示例

// tを含む要素のみを扱うStreamに変換
Stream<String> stream = List.of("twitter", "instagram", "facebook").stream().filter(str -> str.contains("t")); 
// "twitter", "instagram" を扱うStream<String>を返す

// 文字列の文字数を扱うStreamに変換
Stream<Integer> stream = List.of("twitter", "instagram", "facebook").stream().map(str -> str.length());
// 7, 9, 8を扱うStream<Integer>を返す

// IntStream型のStreamに変換
IntStream stream = List.of("twitter", "instagram", "facebook").stream().mapToInt(str -> str.length());
// 7, 9, 8を扱うIntStreamを返す

// 重複を排除
Stream<String> stream = List.of("twitter", "instagram", "facebook", "twitter").stream().distinct();
// "twitter", "instagram", "facebook"を扱うStream<String>を返す

// 要素数を限定する
Stream<String> stream = Stream.generate(() -> new Random().nextInt()).limit(5);
// 5つの乱数を扱うStream<Integer>を返す

// 最初の要素を指定分スキップする
Stream<String> stream = List.of("twitter", "instagram", "facebook").stream().skip(1);
// "instagram", "facebook"を扱うStream<String>を返す

// 要素の順番を並び替える
Stream<String> stream = List.of("twitter", "instagram", "facebook").stream().sorted();
// "facebook", "instagram", "twitter"を扱うStream<String>を返す

// 要素の状態を表示する
Stream<String> stream = List.of("twitter", "instagram", "facebook").stream().peek(str -> System.out.print(str + " "));
// コンソールに twitter instagram facebookと表示し、"twitter", "instagram", "facebook"を扱うStream<String>を返す

// メソッドチェーン
List.of("twitter", "instagram", "facebook").stream().map(str -> str.length()).filter(len -> len > 7);
// 7, 9, 8を扱うStream<Integer>に変換し、9, 8を扱うStream<Integer>を返す

终端操作

这是用于最终处理Stream对象的操作。
每个Stream对象只能调用一次。

以下的示例将在运行时引发异常。

Stream<String> stream = List.of("twitter", "instagram", "facebook").stream();
stream.forEach(str -> System.out.println(str));
stream.forEach(str -> System.out.println(str)); // IllegalStateExceptionがスローされる
终端操作概览
メソッド内容引数戻り値forEachStreamの要素一つ一つに処理を行うConsumervoidcountStreamの要素数を返すなしintcollectStreamの要素を持つコレクションを返すCollector
Supplier, BiConsumer, BiConsumerCollectorで指定した型reduceStreamの要素を結合して返すBinaryOparator
T(初期値), BinaryOperatorOptional<T>
T

请参考Java Stream中的Collectors的注释,因为collect方法的参数Collector很深奥。

// stream要素
Stream<String> stream = List.of("twitter", "instagram", "facebook", "twitter").stream();

// 要素を1つずつコンソールに出力
stream.forEach(str -> System.out.println(str));

// 要素の個数を取得
long count = stream.count();

// 要素をリストにして取得(Collectorsを使用する)
List<String> list  = stream.map(str -> str.toUpperCase()).collect(Collectors.toList());

// 要素をリストにして取得(関数型インタフェースを使用する。↑と同じ)
List<String> list = stream.collect(() -> new ArrayList<>(), 
    (List<String> list, String str) -> list.add(str),
    (List<String> left, List<String> right) -> left.addAll(right)
);

// 要素の文字数を合計して取得
Integer length = stream.map(str -> str.length()).reduce(0, (a, b) -> a + b);

// 初期値を指定しなかった場合はOptionalが返される
Optional<Integer> length = stream.map(str -> str.length()).reduce((a, b) -> a + b);