
Java のストリームは、順次操作または並列操作を実行できる一連の要素です。
「n」回の中間操作があり、最後に端末操作があり、その後に結果が返されます。
ストリームとは
ストリームは、Java 8 で導入された Stream API によって管理できます。
Stream を製造パイプラインとして想像してみてください。このパイプラインでは、いくつかの商品を製造し、仕分けし、出荷のために梱包する必要があります。 Java では、これらの商品はオブジェクトまたはオブジェクトのコレクションであり、操作は製造、仕分け、および梱包であり、パイプラインはストリームです。
ストリームのコンポーネントは次のとおりです。
- 初期入力
- 中間操作
- 端末操作
- 最終結果
Java のストリームのいくつかの機能を調べてみましょう。
- ストリームはメモリ内のデータ構造ではありません。 むしろ、特定のメソッドによって操作される一連の配列、オブジェクト、またはオブジェクトのコレクションです。
- ストリームは本質的に宣言型です。つまり、何を行うかを指定しますが、どのように行うかは指定しません。
- どこにも保管されていないため、一度しか消費できません。
- Stream は元のデータ構造を変更しません。 そこから新しい構造を導き出すだけです。
- パイプラインの最終メソッドから派生した最終結果を返します。
ストリーム API とコレクションの処理
コレクションは、データを格納および処理するメモリ内データ構造です。 コレクションは、データを格納するための Set、Map、List などのデータ構造を提供します。 一方、ストリームは、データをパイプラインで処理した後、効率的に転送する方法です。
ArrayList コレクションの例を次に示します。
import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add(0, 3); System.out.println(list); } } Output: [3]
上記の例でわかるように、ArrayList コレクションを作成し、そこにデータを格納してから、さまざまなメソッドを使用してそのデータを操作できます。
ストリームを使用すると、既存のデータ構造を操作して、新しく変更された値を返すことができます。 以下は、ArrayList コレクションを作成し、ストリームを使用してフィルタリングする例です。
import java.util.ArrayList; import java.util.stream.Stream; public class Main { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList(); for (int i = 0; i < 20; i++) { list.add(i+1); } System.out.println(list); Stream<Integer> filtered = list.stream().filter(num -> num > 10); filtered.forEach(num -> System.out.println(num + " ")); } } #Output [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] 11 12 13 14 15 16 17 18 19 20
上記の例では、既存の list を使用してストリームが作成され、10 より大きい値をフィルター処理するためにリストが反復処理されます。ストリームには何も格納されず、リストが反復処理されるだけで、結果が出力されることに注意してください。 ストリームを出力しようとすると、値ではなくストリームへの参照が取得されます。
Java ストリーム API の作業
Java Stream API は、要素のソース コレクションまたは一連の要素を受け取り、それらに対して操作を実行して最終結果を導き出します。 ストリームは、一連の要素が通過し、何らかの方法で変換される単なるパイプラインです。
ストリームは、次のようなさまざまなソースから作成できます。
- List や Set などのコレクション。
- 配列。
- バッファを使用してファイルとそのパスから。
ストリームで実行される操作には 2 つのタイプがあります。
- 中間操作
- 端末操作
中間操作と端末操作
各中間操作は、指定されたメソッドを使用して入力を変換する新しいストリームを内部的に返します。 実際には何も横断されません。 代わりに、次のストリームに渡されます。 目的の結果を得るためにストリームがトラバースされるのは、端末操作のみです。
たとえば、フィルターで除外して何かにマップしたい 10 個の数値のリストがあるとします。 フィルタリングされた結果を取得して別のものにマップするために、リストのすべての要素がすぐに走査されるわけではありません。 代わりに、個々の要素がチェックされ、条件を満たしていればマップされます。 すべての要素の新しいストリーム。
マップ操作は、リスト全体ではなく、フィルターを満たす個々のアイテムに対して実行されます。 そして、端末操作の時点で、それらはトラバースされ、単一の結果に結合されます。
端末操作を実行すると、ストリームは消費され、それ以上使用できなくなります。 同じ操作を再度実行するには、新しいストリームを作成する必要があります。
ソース: The Bored Dev
ストリームがどのように機能するかを表面レベルで理解したら、Java でのストリームの実装の詳細に飛び込みましょう。
#1。 空のストリーム
Stream API の empty メソッドを使用して、空のストリームを作成します。
import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream emptyStream = Stream.empty(); System.out.println(emptyStream.count()); } } Output: 0
ここで、このストリームの要素数を出力すると、要素のない空のストリームであるため、出力として 0 が得られます。 空のストリームは、null ポインター例外を回避するのに非常に役立ちます。
#2。 コレクションからのストリーム
Lists や Set などのコレクションは、コレクションからストリームを作成できる stream() メソッドを公開します。 その後、作成されたストリームをトラバースして、最終結果を取得できます。
ArrayList<Integer> list = new ArrayList(); for (int i = 0; i < 20; i++) { list.add(i+1); } System.out.println(list); Stream<Integer> filtered = list.stream().filter(num -> num > 10); filtered.forEach(num -> System.out.println(num + " ")); #Output [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] 11 12 13 14 15 16 17 18 19 20
#3。 配列からのストリーム
Arrays.stream() メソッドは、配列からストリームを作成するために使用されます。
import java.util.Arrays; public class Main { public static void main(String[] args) { String[] stringArray = new String[]{"this", "is", "etechjp.com"}; Arrays.stream(stringArray).forEach(item -> System.out.print(item + " ")); } } #Output this is etechjp.com
ストリームを作成する要素の開始インデックスと終了インデックスを指定することもできます。 開始インデックスは包括的ですが、終了インデックスは排他的です。
String[] stringArray = new String[]{"this", "is", "etechjp.com"}; Arrays.stream(stringArray, 1, 3).forEach(item -> System.out.print(item + " ")); Output: is etechjp.com
#4。 ストリームを使用して最小数と最大数を見つける
コレクションまたは配列の最大数と最小数にアクセスするには、Java の Comparators を使用します。 min() および max() メソッドはコンパレータを受け入れ、Optional オブジェクトを返します。
Optional オブジェクトは、null 以外の値を含む場合と含まない場合があるコンテナー オブジェクトです。 null 以外の値が含まれている場合、 get() メソッドを呼び出すと値が返されます。
import java.util.Arrays; import java.util.Optional; public class MinMax { public static void main(String[] args) { Integer[] numbers = new Integer[]{21, 82, 41, 9, 62, 3, 11}; Optional<Integer> maxValue = Arrays.stream(numbers).max(Integer::compare); System.out.println(maxValue.get()); Optional<Integer> minValue = Arrays.stream(numbers).min(Integer::compare); System.out.println(minValue.get()); } } #Output 82 3
学習リソース
Java での Streams の基本的な理解ができたので、Java 8 に精通するための 5 つのリソースを以下に示します。
#1。 Java 8 の動作
この本は、ストリーム、ラムダ、関数型プログラミングなど、Java 8 の新機能を紹介するガイドです。 クイズや知識チェックの質問も本に含まれており、学んだことを復習するのに役立ちます。
この本は、ペーパーバック形式と Amazon のオーディオブック形式で入手できます。
#2。 Java 8 ラムダ: 一般向けの関数型プログラミング
この本は、コア Java SE 開発者に Lambda 式の追加が Java 言語にどのように影響するかを教えるために特別に設計されています。 Java 8 ラムダ式を習得するための、滑らかな説明、コード演習、および例が含まれています。
ペーパーバック形式と Amazon の Kindle 版で入手できます。
#3。 本当にせっかちな人のための Java SE 8
あなたが経験豊富な Java SE 開発者である場合、この本は、Java SE 8 で行われた改善、ストリーム API、ラムダ式の追加、Java での並行プログラミングの改善、およびほとんどの人が知らない Java 7 の機能について説明します。知りません。
Amazonではペーパーバック形式でのみ入手可能です。
#4。 Lambda と Streams を使用した Java 関数型プログラミングを学ぶ
Udemy によるこのコースでは、Java 8 および 9 での関数型プログラミングの基礎を探ります。ラムダ式、メソッド参照、ストリーム、および関数型インターフェイスは、このコースが焦点を当てている概念です。
また、関数型プログラミングに関連する一連の Java パズルと演習も含まれています。
#5。 Java クラス ライブラリ
Java クラス ライブラリは、Coursera が提供する Core Java Specialization の一部です。 Java Generics を使用してタイプ セーフなコードを記述する方法、4000 を超えるクラスで構成されるクラス ライブラリを理解する方法、ファイルを操作する方法、実行時エラーを処理する方法について説明します。 ただし、このコースを受講するにはいくつかの前提条件があります。
- Java入門
- Javaによるオブジェクト指向プログラミングの紹介
- Java のオブジェクト指向階層
最後の言葉
Java Stream API と Java 8 での Lambda 関数の導入により、並列反復、関数型インターフェイス、コードの削減など、Java の多くのことが簡素化および改善されました。
ただし、ストリームにはいくつかの制限があります。 最大の制限は、一度しか消費できないことです。 あなたが Java 開発者であれば、上記のリソースはこれらのトピックをより詳細に理解するのに役立つので、ぜひチェックしてみてください。
Java での例外処理についても知りたいと思うかもしれません。