はじめに
皆さん。こんにちは!
DreamHanksの254cmです。
今回はStream APIについて説明していきます。
Java記事のまとめはこちらです。
前回の記事は【Java開発】第27回 Lambdaです。
Stream APIとは?
Stream APIはJava8から追加された機能であり、リストや配列なのに格納されている複数のデータをより簡単に操作できる技術です。
ストリームは配列やリストように複数のデータを格納できるオブジェクトであり、入力されたデータを操作するメソッドを持っています。
しかし、ストリームも複数のデータを格納することができますが、Javaはストリームを利用してデータを管理するのは推奨されていません。
ただ、入力されたデータに対する処理を行うべきです。
Streamの動作
ストリームは下記のように三つの段階で動作します。
1. Streamインスタンス生成
2. データを絞り込む中間作業
3. 絞り込んだデータを加工する最終演算
に構成されています。
Stream APIの特徴
1. 最終演算が終わったストリームは再使用できません。ストリームがデータを加工するとき、データを
一つずつ取り出して加工するので、最終演算が終わった時にはストリームにデータが入っていないの
で、再活用ができません。
2.ストリームの演算は「Iterator」と異なり、現本のデータに影響を与えません。
つまり、処理が行われた別途の結果物を返還します。
3.ストリームの処理は for, whileなので実装された処理より性能が高いです。
Streamの生成
サンプル1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class CreateStreamSample { public static void main(String[] args) { ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(3); arrayList.add(46); arrayList.add(2); arrayList.add(10); Stream<Integer> listToStream = arrayList.stream(); //リストのstreamメソッドで生成 listToStream.forEach(System.out::println);// メソッド参照 listToStream.forEach(System.out::println); } } |
上記のようにCollectionFrameworkのクラスはstream()メソッドを使ってストリームを生成できます。
forEachという最終演算を行ったストリームをまた再活用すると「IllegalStateException」が発生されます。
実行結果
1 2 3 4 5 6 7 8 |
3 46 2 10 Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed at java.base/java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) at practiceProject.CreateStreamSample.main(CreateStreamSample.java:18) |
サンプル2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class CreateStreamSample { public static void main(String[] args) { String[] items = new String[]{"item4","item1","item3","item2"}; Stream<String> itemStream = Arrays.stream(items); for(String item : items) { // Stream APIではない場合 System.out.println("item : " + item); } itemStream.forEach(e -> System.out.println("item : " + e)); //Stream APIの場合 } } |
配列の場合、Arraysクラスのstreamメソッドを利用してStreamを生成します。
上記のサンプルでストリームを利用した処理と利用していない処理を比べています。
ストリームを利用すると既存の処理より作成するソースコードの量を減らすことができます。
実行結果
1 2 3 4 5 6 7 8 |
item : item4 item : item1 item : item3 item : item2 item : item4 item : item1 item : item3 item : item2 |
サンプル3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class CreateStreamSample { public static void main(String[] args) { Stream<String> stream1 = Stream.of("一","二","三","四","五");// 直接値を入れてストリーム生成 stream1.forEach(e -> System.out.print(e + " ")); System.out.println(); IntStream stream2 = IntStream.range(0, 6); //0以上6未満の値を持つストリーム stream2.forEach(e -> System.out.print(e + " ")); System.out.println(); LongStream stream3 = LongStream.rangeClosed(0, 5);//0以上5以下の値を持つストリーム生成 stream3.forEach(e -> System.out.print(e + " ")); } } |
実行結果
1 2 3 |
一 二 三 四 五 0 1 2 3 4 5 0 1 2 3 4 5 |
中間作業と最終演算
〇中間作業
〇終了演算
以外にもいろんな処理がありますが、よく使われるメソッドは以上のようになります。
詳しい説明はこちらのリンクを参照していただくと嬉しいです。
Stream API活用サンプル
サンプル1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class StreamSample { public static void main(String[] args) { List<String> strings = new ArrayList<String>(); strings.add("apple"); strings.add("orange"); strings.add("test"); strings.add("gyuudonn"); List<String> filteredResult = strings.stream() .filter(e -> !(e.contains("a"))) // aを含まれていない単語を絞り込む .collect(Collectors.toList()); //返還されたストリームをリストに変換 filteredResult.stream().forEach(System.out::println); } } |
上記のサンプルはよく使われるパータンの一つであり、streamメソッドでストリームを生成、
filterでデータを絞り込む、collectで結果を取得の段階で構成されています。
下記のようなストリームを使わずに実装したソースコードより作成する量が少ないです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class ExampleCalss { public static void main(String[] args) { List<String> strings = new ArrayList<String>(); strings.add("apple"); strings.add("orange"); strings.add("test"); strings.add("gyuudonn"); List<String> filteredResult = new ArrayList<String>(); for(String item : strings) { if(!(item.contains("a"))) { filteredResult.add(item); } } for(String item : filteredResult) { System.out.println(item); } } } |
実行結果
1 2 |
test gyuudonn |
サンプル2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class StreamSample { public static void main(String[] args) { List<Integer> numbers = new ArrayList<Integer>(); numbers.add(4); numbers.add(2); numbers.add(6); numbers.add(10); numbers.add(1); int sum = numbers.stream().reduce(0, (a,b) -> a+b); System.out.println(sum); } } |
上記のように配列の値を取り出して合計を求める処理に使われます。
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class StreamSample { public static void main(String[] args) { List<Integer> numbers = new ArrayList<Integer>(); numbers.add(4); numbers.add(2); numbers.add(6); numbers.add(10); numbers.add(1); int sum = numbers.stream().reduce(0, (a,b) -> a+b); System.out.println(sum); } } |
サンプル3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class StreamSample { public static void main(String[] args) { List<String> items = new ArrayList<String>(); items.add("a"); items.add("b"); items.add("c"); items.add("d"); List<String> mappedItems = items.stream().map(e -> "item : "+ e).collect(Collectors.toList()); //リストの要素に一括処理 System.out.println(items); System.out.println(mappedItems); } } |
上記のサンプルはリストの要素に一連の処理を適用したいときに使われます。
実行結果
1 2 |
[a, b, c, d] [item : a, item : b, item : c, item : d] |
終わりに
今回の記事は以上になります。
次回は匿名内部クラスを学びましょう。
ご覧いただきありがとうございます。
コメント