Java 8ストリームの概要
1. 概要
この記事では、Java8が追加した主要な新機能の1つであるストリームについて簡単に説明します。
ストリームとは何かを説明し、簡単な例を使用して作成と基本的なストリーム操作を紹介します。
2. ストリームAPI
Java 8の主な新機能の1つは、要素のシーケンスを処理するためのクラスを含むストリーム機能(java.util.stream)の導入です。
中心的なAPIクラスはStream<T>.です。次のセクションでは、既存のデータプロバイダーソースを使用してストリームを作成する方法を示します。
2.1. ストリームの作成
ストリームは、さまざまな要素ソースから作成できます。 stream()およびof()メソッドを使用したコレクションまたは配列:
String[] arr = new String[]{"a", "b", "c"};
Stream stream = Arrays.stream(arr);
stream = Stream.of("a", "b", "c");
stream()のデフォルトメソッドがCollectionインターフェイスに追加され、任意のコレクションを要素ソースとして使用してStream<T>を作成できるようになります:
Stream stream = list.stream();
2.2. ストリームを使用したマルチスレッド
Stream APIは、並列モードでストリームの要素に対して操作を実行するparallelStream()メソッドを提供することにより、マルチスレッド化も簡素化します。
以下のコードでは、ストリームのすべての要素に対してメソッドdoWork()を並列に実行できます。
list.parallelStream().forEach(element -> doWork(element));
次のセクションでは、いくつかの基本的なStream API操作を紹介します。
3. ストリーム操作
ストリームで実行できる便利な操作は数多くあります。
それらはintermediate operations(Stream<T>を返す)とterminal operations(確定型の結果を返す)に分けられます。 中間操作では、連鎖が可能です。
ストリームの操作によってソースが変更されないことにも注意してください。
以下に簡単な例を示します。
long count = list.stream().distinct().count();
したがって、distinct()メソッドは、前のストリームの一意の要素の新しいストリームを作成する中間操作を表します。 また、count()メソッドは、ストリームのサイズを返すターミナル操作,です。
3.1. 繰り返し
Stream APIは、for, for-eachおよびwhileループを置き換えるのに役立ちます。 これにより、操作のロジックに集中できますが、要素のシーケンス全体の反復には集中できません。 例えば:
for (String string : list) {
if (string.contains("a")) {
return true;
}
}
このコードは、Java 8コードの1行だけで変更できます。
boolean isExist = list.stream().anyMatch(element -> element.contains("a"));
3.2. フィルタリング
filter()メソッドを使用すると、述語を満たす要素のストリームを選択できます。
たとえば、次のリストを考えてください。
ArrayList list = new ArrayList<>();
list.add("One");
list.add("OneAndOnly");
list.add("Derek");
list.add("Change");
list.add("factory");
list.add("justBefore");
list.add("Italy");
list.add("Italy");
list.add("Thursday");
list.add("");
list.add("");
次のコードは、List<String>のStream<String>を作成し、char “d”を含むこのストリームのすべての要素を検索し、フィルター処理された要素のみを含む新しいストリームを作成します。
Stream stream = list.stream().filter(element -> element.contains("d"));
3.3. マッピング
特別な関数を適用してStreamの要素を変換し、これらの新しい要素をStreamに収集するには、map()メソッドを使用できます。
List uris = new ArrayList<>();
uris.add("C:\\My.txt");
Stream stream = uris.stream().map(uri -> Paths.get(uri));
したがって、上記のコードは、最初のStreamのすべての要素に特定のラムダ式を適用することにより、Stream<String>をStream<Path>に変換します。
すべての要素に独自の要素シーケンスが含まれているストリームがあり、これらの内部要素のストリームを作成する場合は、flatMap()メソッドを使用する必要があります。
List details = new ArrayList<>();
details.add(new Detail());
Stream stream
= details.stream().flatMap(detail -> detail.getParts().stream());
この例では、タイプDetail.の要素のリストがあります。Detailクラスには、flatMap()の助けを借りてList<String>.であるフィールドPARTS,が含まれています。メソッドフィールドPARTSのすべての要素が抽出され、新しい結果のストリームに追加されます。 その後、最初のStream<Detail>は失われます.
3.4. マッチング
Stream APIは、いくつかの述語に従ってシーケンスの要素を検証するための便利な機器のセットを提供します。 これを行うには、次のいずれかの方法を使用できます。anyMatch(), allMatch(), noneMatch().それらの名前は自明です。 これらはブール値を返す端末操作です。
boolean isValid = list.stream().anyMatch(element -> element.contains("h")); // true
boolean isValidOne = list.stream().allMatch(element -> element.contains("h")); // false
boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h")); // false
3.5. 削減
Stream APIでは、タイプStreamのreduce()メソッドを使用して、指定された関数に従って要素のシーケンスをある値に減らすことができます。 このメソッドは2つのパラメーターを取ります。1つ目は開始値、2つ目はアキュムレーター関数です。
List<Integer>があり、これらすべての要素といくつかの初期Integerの合計(この例では23)が必要だとします。 したがって、次のコードを実行すると、結果は26(23 + 1 + 1 + 1)になります。
List integers = Arrays.asList(1, 1, 1);
Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);
3.6. 収集
削減は、タイプStream.のcollect()メソッドによっても提供できます。この操作は、ストリームをCollectionまたはMapに変換し、ストリームを表す場合に非常に便利です。単一の文字列.の形式ほとんどすべての一般的な収集操作のソリューションを提供するユーティリティクラスCollectorsがあります。 簡単ではない一部のタスクでは、カスタムCollectorを作成できます。
List resultList
= list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());
このコードは、ターミナルcollect()操作を使用して、Stream<String>をList<String>.に減らします。
4. 結論
この記事では、Javaストリームについて簡単に触れました。これは間違いなく最も興味深いJava 8機能の1つです。
Streamsを使用するはるかに高度な例があります。この記事の目的は、機能を使用して開始できることを迅速かつ実用的に紹介すること、および探索とさらなる学習の開始点としてのみを提供することでした。
記事に付随するソースコードは利用可能ですover on GitHub.