ストリーム中間処理
- ストリームを流れる値を加工、フィルターする
- 実行されるのは終端処理が呼ばれたタイミング
指定条件で値をフィルタ
- filterメソッド
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of(
"https://qiita.com/",
"Neko",
"CAT",
"https://www.amazon.co.jp/",
"https://ja.wikipedia.org/wiki/Neko_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)"
)
.filter(s -> s.startsWith("https://"))
.forEach(System.out::println);
/*
https://qiita.com/
https://www.amazon.co.jp/
https://ja.wikipedia.org/wiki/Neko_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)
*/
}
}
与えられた値を加工
- mapメソッド
- 文字列リストを文字列長リストに変換して出力
- 生成された直後は
String<String>
で、mapメソッドを経たらString<Integer>
になる
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of("Munchkin", "Siamese", "Persian", "Scottish Fold", "Tama")
.map(s -> s.length())
.forEach(System.out::println); //8 7 7 13 4
}
}
- 基本型ストリームを生成するmapToInt/mapToLong/mapToDoubleメソッド
-
String<Integer>
ではなくIntStream
が生成される - ボクシングの負担減少
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of("Munchkin", "Siamese", "Persian", "Scottish Fold", "Tama")
.mapToInt(s -> s.length())
.forEach(System.out::println); //8 7 7 13 4
}
}
与えられた要素を加工
- flatMap/flatMapToXXメソッド
- 変換結果をStream型で返すのがmapとの違い
- 個々の要素で返したStreamが最終的に結合されて返る
//二次元配列listを一次元配列に変換
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
var list = new String[][] {
{ "neko", "nekko", "nekkko" },
{ "inu", "innu" },
{ "tori", "torri" }
};
//flatMapで入れ子の配列を渡し、Arrays.streamメソッドでストリーム化
//flatMapで連結することで一次元配列にフラット化
Arrays.stream(list)
.flatMap(v -> Arrays.stream(v))
.forEach(System.out::println);
// neko nekko nekkko inu innu tori torri
}
}
- ストリーム加工の際に入れ子で値を加工することも可能
//二次元配列をフラット化する際に頭文字を取り出す
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
var list = new String[][] {
{ "neko", "nekko", "nekkko" },
{ "inu", "innu" },
{ "tori", "torri" }
};
Arrays.stream(list)
.flatMap(v -> Arrays.stream(v).map(str -> str.substring(0, 1)))
.forEach(System.out::println);
//n n n i i t t
}
}
要素を並び替える
- sortedメソッド
- 自然順序によるソート
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of("Munchkin", "Siamese", "Persian", "Scottish Fold", "Tama")
.sorted()
.forEach(System.out::println);
// Munchkin
// Persian
// Scottish Fold
// Siamese
// Tama
}
}
- 規則を設定したい場合、ラムダ式で設定
import java.util.stream.Stream;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
Stream.of("Munchkin", "Siamese", "Persian", "Scottish Fold", "Tama")
.sorted((str1, str2) -> str1.length() - str2.length())
.forEach(System.out::println);
// Tama
// Siamese
// Persian
// Munchkin
// Scottish Fold
/*Comparatorインターフェースで辞書逆順
Stream.of("Munchkin", "Siamese", "Persian", "Scottish Fold", "Tama")
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
*/
}
}
m~n番目の要素を取り出す
- skip/limitメソッド
- skipメソッド:m番目までの要素を切り捨てる
- limitメソッド:n+1番目以降の要素を切り捨てる
//skipで4要素をスキップし、limitでそこから10個分の要素を取り出す
import java.util.stream.IntStream;
public class StreamLimit {
public static void main(String[] args) {
IntStream.range(1, 20)
.skip(4)
.limit(10)
.forEach(System.out::println); //5,6,7,8,9,10,11,12,13,14
}
}
先頭から条件をみたす間の値を除去
- dropWhileメソッド
- 条件式に合致してる値をスキップ
- ストリームの先頭から負数を除去
- あくまでも先頭から連続する値なので途中の負数は除去しない
- →途中の場合はfilterで除去
import java.util.stream.IntStream;
public class StreamDrop {
public static void main(String[] args) {
IntStream.of(-2, -5, 0, 3, -1, 2)
.dropWhile(i -> i < 0)
.forEach(System.out::println); //0,3,-1,2
}
}
先頭から条件を満たす間の値のみ取り出す
- takeWhileメソッド
- ストリームの先頭から負数であるものだけを処理する
- あくまでも処理するのは先頭から連続する値
import java.util.stream.IntStream;
public class StreamTake {
public static void main(String[] args) {
IntStream.of(-2, -5, 0, 3, -1, 2)
.takeWhile(i -> i < 0)
.forEach(System.out::println); //-2,-5
}
}
ストリームの途中状態を確認する
- peekメソッド
- 途中で任意の処理を挟むことができる
- peekメソッドはストリームに影響を及ぼさない
//ソート前後でストリーム内容を出力
import java.util.stream.Stream;
public class StreamPeek {
public static void main(String[] args) {
Stream.of("さかな", "あか", "こだま", "きんもくせい")
.peek(System.out::println)
.sorted()
.forEach(System.out::println);
}
}
値の重複を除去
- distinctメソッド
- ストリームに含まれる値の重複を除去
- 任意のクラスの特定フィールドをキーに重複除去できない
- →filterメソッドを使う
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of("ねこ", "猫", "ねっこ", "ねこ", "ねこねこ")
.distinct()
.forEach(System.out::println);
// ねこ
// 猫
// ねっこ
// ねこねこ
}
}
- Personクラスでnameフィールドをキーに重複をチェック
import java.util.HashSet;
import java.util.stream.Stream;
public class StreamDistinctObj {
public static void main(String[] args) {
var set = new HashSet<String>();
Stream.of(
new Person("山田", 40),
new Person("高野", 30),
new Person("大川", 35),
new Person("山田", 45)
)
//filterメソッドの中で値をHashSetに追加
//HashSet.addメソッドは値を追加できなかった(重複)場合falseを返す
.filter(p -> set.add(p.name))
.forEach(System.out::println);
}
}
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return String.format("%s(%d歳)", this.name, this.age);
}
}
基本型ストリームの変換
- asLongStream/asDoubleStream/LongStreamで型変換
//IntStreamからDoubleStreamへの変換
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
IntStream.range(1, 5)
.asDoubleStream()
.forEach(System.out::println);
//1.0 2.0 3.0 4.0
}
}
基本型、参照型ストリームを相互変換
- 基本型から参照型:boxedメソッド
- 参照型から基本型:mapToObjメソッド
//IntStreamからStream<Integer>に変換
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
IntStream.range(1, 5)
.boxed()
.forEach(System.out::println);
//1 2 3 4
IntStream.range(1, 5)
.mapToObj(Integer::valueOf)
.forEach(System.out::println);
//1 2 3 4
}
}
//Stream<Integer>からIntStreamに変換
import java.util.stream.Stream;
public class StreamUnboxed {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.mapToInt(i -> i) //アンボクシングでInteger→int
.forEach(System.out::println); //1 2 3 4
}
}