ストリームAPI
java.util.Optionalクラス
Optionalは、値が存在するかどうかを表現するために使用される。
値が存在しない場合にnullを扱う代わりに、Optionalを使用することで明示的に値の存在または不在を表現することができる。
メリット
-
nullチェックの簡略化
明示的に値が存在しない場合を考慮できる。
これにより、NullPointerExceptionを回避することができる。 -
読みやすさと安全性の向上
値の存在性チェック、値が存在しない場合のデフォルト値の提供などを実行することができる。
つまり、簡潔かつ安全に値の存在性を確認し、適切な処理を行うことができる。
Optionalインスタンスを作成する際に使用する。
- empty()メソッド
- orElse()メソッド
- of()メソッド
- ofNullable()メソッド
メソッド | インスタンスの中身 | 使う場面 |
---|---|---|
empty | 空 | 値が存在しないことを明示する場合 |
of | null以外の値 | 値でnullを許容したくない場合 |
ofNullable | nullを含む値 | 値がnullである可能性がある場合 |
- of()メソッドはnullの場合、例外をスローする。
- 上の表にないorElse()メソッドは、Optionalインスタンスが空の場合に
デフォルトの値を設定することができる。
get()
Optionalクラスからのインスタンスから値を取り出す方法
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.of("Hello");
System.out.println(optional.get());
}
}
Hello
空のOptionalのインスタンスからは値を取りだせない。
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
System.out.println(optional.get());
}
}
java.util.NoSuchElementExceptionが発生
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.ofNullable(null);
System.out.println(optional.get());
}
}
java.util.NoSuchElementExceptionが発生
public static <T> Optional<T> empty()
空のOptionalインスタンスを返します。このOptionalの値は存在しません。
型パラメータ:
T - 存在しない値の型
戻り値:
空のOptional。
Optional<String> emptyOptional = Optional.empty();
- 上記の例では、empty()メソッドを呼び出して空のOptionalオブジェクトを生成し、それをemptyOptional変数に代入している。
- 空のOptionalオブジェクトは、値が存在しないことを明示的に表現するために使用される。
- 値が存在しない場合、Optionalのメソッドを使用して値の取得や処理を行うときに、orElse()メソッドやof()メソッドを使用することもできる。
public T orElse(T other)
存在する場合は値を返し、それ以外の場合はotherを返します。
パラメータ:
other - 存在する値がない場合に返される値、nullも可
戻り値:
値(存在する場合)、それ以外の場合はother
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
System.out.println(optional.orElse("Default Value"));
}
}
Default Value
- 上記の例では、orElse()メソッドを使用してデフォルト値"Default Value"を指定している。
- 値が存在しない場合には、デフォルト値が返される。
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.of("A");
System.out.println(optional.orElse("B"));
}
}
A
public T orElseGet(Supplier<? extends T> other)
値が存在する場合はその値を返し、そうでない場合はotherを呼び出し、その呼び出しの結果を返します。
パラメータ:
other - Supplier(値が存在しない場合は、これの結果が返される)
戻り値:
値(存在する場合)、それ以外の場合はother.get()の結果
例外:
NullPointerException - 値が存在せずotherがnullの場合
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
System.out.println(optional.orElseGet(() -> "Default Value"));
}
}
Default Value
public T orElseThrow()
値がある場合は値を返し、そうでない場合はNoSuchElementExceptionをスローします。
戻り値:
このOptionalによって記述される非null値
例外:
NoSuchElementException - 値が存在しない場合
import java.util.NoSuchElementException;
import java.util.Optional;
public class OptionalSample {
public static void main(String[] args) {
String str = null;
Optional<String> value = Optional.ofNullable(str);
try {
str = value.orElseThrow();
System.out.println(str);
} catch (NoSuchElementException ex) {
System.out.println("NoSuchElementExceptionです");
}
}
}
NoSuchElementExceptionです
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable
値が存在する場合は、その含まれている値を返し、それ以外の場合は、指定されたサプライヤによって作成された例外をスローします。
型パラメータ:
X - スローされる例外の型
パラメータ:
exceptionSupplier - スローされる例外を返すサプライヤ
戻り値:
存在する値
例外:
X - 存在する値がない場合
NullPointerException - 値が存在せずexceptionSupplierがnullの場合
X extends Throwable
import java.util.Optional;
public class OptionalSample {
public static void main(String[] args) {
String str = null;
Optional<String> value = Optional.ofNullable(str);
try {
System.out.println(value.orElseThrow(() -> new RuntimeException()));
} catch (RuntimeException e) {
System.out.println("RuntimeExceptionです");
}
}
RuntimeExceptionです
public static <T> Optional<T> of(T value)
nullでない値を保持するOptionalインスタンスを作成する。
型パラメータ:
T - 値のクラス
パラメータ:
value - 存在する値、非nullである必要がある
戻り値:
存在する値でのOptional
例外:
NullPointerException - valueがnullの場合。
String value = "Hello";
Optional<String> optional = Optional.of(value);
- 上記の例では、of()メソッドを使用して、valueがnullでないことを前提として値を含むOptionalインスタンスを生成し、optional変数に代入している。
String value = null;
Optional<String> optional = Optional.of(value);
- 上記の例では、valueがnullであるため、of()メソッドはNullPointerExceptionをスローする。
※of()メソッドを使用する際には、値がnullでないことを確認する必要がある。
値がnullである可能性がある場合には、代わりにofNullable()メソッドを
使用することが推奨される。
public static <T> Optional<T> ofNullable(T value)
指定された値がnullでない場合はその値を記述するOptionalを返し、それ以外の場合は空のOptionalを返します。
型パラメータ:
T - 値のクラス
パラメータ:
value - 記述する値(nullも可)
戻り値:
指定された値がnullでない場合は存在する値でのOptional、それ以外の場合は空のOptional
String value = "Hello";
Optional<String> optional = Optional.ofNullable(value);
上記の例では、ofNullable()メソッドを使用して、valueがnullでない場合は値を含むOptionalインスタンスを生成し、optional変数に代入している。
String value = null;
Optional<String> optional = Optional.ofNullable(value);
上記の例では、valueがnullであるため、ofNullable()メソッドは空のOptionalインスタンスを生成している。
ofNullable()メソッドを使用することで、値がnullであるかどうかを判定せずに、値を含むか空のOptionalインスタンスを作成することができる。
これは、値の存在または不在を明示的に表現するために使用される。
public boolean isPresent()
存在する値がある場合はtrueを返し、それ以外の場合はfalseを返します。
戻り値:
存在する値がない場合はtrue、それ以外の場合はfalse
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
if (optional.isPresent()) {
System.out.println(optional.get());
}
}
}
何も表示されない
public void ifPresent(Consumer<? super T> consumer)
値が存在する場合は指定されたコンシューマをその値で呼び出し、それ以外の場合は何も行いません。
パラメータ:
consumer - 値が存在する場合に実行されるブロック
例外:
NullPointerException - 値が存在しconsumerがnullの場合
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.of("test");
optional.ifPresent((str)) -> System.out.println(str));
}
}
test
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
optional.ifPresent((str) -> System.out.println(str));
}
}
何も表示されない
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
値が存在する場合は、指定されたアクションを値とともに実行し、そうでない場合は空のベースのアクションを実行します。
値がある場合は第1引数で指定したラムダ式(Consumer型)を実行し、値がない場合は第2引数で指定したラムダ式(Runnable型)を実行する。
パラメータ:
action - 値が存在する場合、実行されるアクション
emptyAction - 値が存在しない場合、実行される空のベースのアクション
例外:
NullPointerException - 値が存在し、指定されたアクションがnullの場合、または値が存在しない場合、指定された空のアクションはnullです。
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
optional.ifPresentOrElse((str) -> System.out.println(str), () -> System.out.println("empty"));
}
}
empty
public boolean isEmpty()
値が存在しない場合はtrue、それ以外の場合falseを返します。
戻り値:
値が存在しない場合はtrue、それ以外の場合はfalse
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
if (optional.isEmpty()) {
System.out.println("empty");
return;
}
System.out.println(optional.get());
}
}
empty
public <U> Optional<U> map(Function<? super T,? extends U> mapper)
値が存在する場合は、与えられたマッピング関数をその値に適用した結果を(ofNullable(T)のように)記述するOptionalを返します。それ以外の場合は、空のOptionalを返します。
マッピング関数がnullの結果を返した場合、このメソッドは空のOptionalを返します。
型パラメータ:
U - マッピング関数から返される値の型
パラメータ:
mapper - 存在する場合、値に適用するマッピング関数
戻り値:
値が存在する場合はマッピング関数をこのOptionalの値に適用した結果を記述するOptional、それ以外の場合は空のOptional
例外:
NullPointerException - マッピング関数がnullの場合
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optionalA = Optional.of("test");
Optional<String> optionalB = optionalA.map(str -> str.toUpperCase());
System.out.println(optionalA.get());
System.out.println(optionalB.get());
}
}
test
TEST
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optionalA = Optional.ofNullable(null);
Optional<String> optionalB = optionalA.map(str -> str.toUpperCase());
System.out.println(optionalB.isEmpty());
}
}
例外が発生せずに何も出力されない
public <U> Optional<U> flatMap(Function<? super T,? extends Optional<? extends U>> mapper)
値が存在する場合、指定されたOptional-bearingマッピング関数を値に適用した結果を返します。それ以外の場合は空のOptionalを返します。
型パラメータ:
U - マッピング関数によって返されたOptionalの値の型
パラメータ:
mapper - 存在する場合、値に適用するマッピング関数
戻り値:
値が存在する場合はOptional生成マッピング関数をこのOptionalの値に適用した結果、それ以外の場合は空のOptional
例外:
NullPointerException - マッピング関数がnullの場合、またはnullの結果を返す場合
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optionalA = Optional.of("test");
Optional<String> optionalB = optionalA.flatMap(str -> test(str));
System.out.println(optionalB.get());
}
private static Optional<String> test(String str) {
return Optional.of(str.toUpperCase());
}
}
TEST
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> optionalA = Optional.of("test");
Optional<String> optionalB = optionalA.map(str -> test(str));
System.out.println(optionalB.get());
}
private static Optional<String> test(String str) {
return Optional.of(str.toUpperCase());
}
}
testメソッドは、String型を扱うOptionalのインスタンスへの参照を戻す。そのため、mapメソッドはこの参照を持った新しいOptionalのインスタンスを生成することになる。
つまり、Optionalの中にOptionalへの参照が入れ子で入ることになる。Optional<Optional<String>>型の値を戻すが戻り値を受け取る変数の型がOptional<String>のため、コンパイルエラー
OptionalDoubleクラス
public double getAsDouble()
結果の値をdouble型で返す
メソッド参照
import java.util.List;
public class Sample {
public static void main (String[] args) {
List<Integer> list = List.of(1, 2, 3, 4, 5);
list.forEach(System.out::println); // メソッド参照
}
}
1
2
3
4
5
ストリームAPI
- StreamAPIとはJava SE 8で新たに導入された「データ集合の操作用API」。
- データ集合の個々のデータに対して様々な操作を順次行うことができる。
- for文などの繰り返し構文を置き換えるために用意されていない。
ストリームを利用する理由
- コレクションや配列の全要素を同じように変換するため。
- コレクションや配列の要素の合計や平均といった統計を取るため。
- コレクションや配列の要素を何らかの条件でグルーピングするため。
- コレクションや配列の要素から条件にあったデータを検索するため。
ストリームの処理順
コレクションが管理する順で処理される。
Streamインタフェースの種類
中間操作
- 取り出した要素に加える処理のこと。
- ストリームオブジェクトを返す。
- メソッド呼び出しの時点で処理が実行される訳ではなく、
- 終端操作の実行時に実行される→遅延評価
- 終端操作が適応されるまで何度も(0回以上)適応することができる。
終端操作
- 中間操作を終えた要素の集合に対して行う最終処理のこと。
- 処理の最後に一度だけ適応することができる。
- 終端操作が適用されたストリームに対して再度ストリーム処理を適用することはできない。
→再度ストリーム処理を行おうとすると「実行時に例外がスローされる」
処理を行うメソッド | 概要 |
---|---|
distinct | 要素の重複を除いたストリームを戻す。 |
filter | 引数に指定した条件に一致する要素だけで構成されるストリームを戻す。 |
limit | ストリームの要素を、指定された数に切り詰めた結果のストリームを戻す。 |
map | 指定された関数を要素に適用した結果のストリームを戻す。 |
peek | 新しい結果のストリームを生成し、指定された関数を適用して戻す。 |
skip | 引数で指定した最初のn個の要素を破棄し、残った要素で構成されるストリームを戻す。 |
sorted | このストリームの要素を自然順序に従ってソートした結果から構成されるストリームを戻す。 |
処理を行うメソッド | 概要 |
---|---|
allMatch | ストリーム内のすべての要素が条件に一致するかどうかを調べる。 |
anyMatch | ストリーム内のいずれかの要素が条件に一致するどうかを調べる。 |
collect | ストリームの要素を持つコレクションを戻す。 |
count | ストリーム内の要素を数える。 |
findAny | ストリーム内に要素が残っているかどうかの結果を持つ。Optionalを戻す。 |
findFirst | ストリーム内の最初の要素を持ったOptionalを戻す。 |
forEach | ストリーム内の要素を使って繰り返し処理を実行する。 |
max | ストリーム内の最大の要素を戻す。 |
min | ストリーム内の最小の要素を戻す。 |
noneMatch | ストリーム内の要素で条件に一致するものがないかどうかを調べる。 |
reduce | ストリーム内の要素を累積的に結合していくリダクション処理を実行する。 |
toArray | ストリームの要素を含む配列を戻す。 |
配列からストリームを作る
String[] array = {"A", "B", "C"}
Stream<String> stream = Arrays.stream(array);
IntStream intStream = Arrays.stream(array);
※プリミティブ型(int、long、double)を扱う場合は、IntStream、LongStream、DoubleStreamを使用する
中間操作のメソッド
Stream<T> filter(Predicate<? super T> predicate)
predicateの記述に一致するストリームを返す。
import java.util.Arrays;
import java.util.List;
public class FilterSample {
public static void main(Stringl] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream()
.filter(x -> x % 2 == 0)
.forEach(System.out::println);
}
}
2
4
6
8
10
import java.util.List;
import java.util.Optional;
public class FilterSample {
public static void main(Stringl] args) {
List<Item> items = List.of(
new Item("A", 100),
new Item("B", 200),
new Item("C", 300)
);
Stream itemStream = items.stream();
itemStream.filter(item -> item.getPrice() > 200)
.forEach(System.out::println);
}
}
①
itemStreamのfilterメソッドに渡す引数を「item -> ((Item) item).getPrice() > 200」に置き換える。
②
変数itemStreamのデータ型をStreamからStream<Item>に置き換える
Stream型は型パラメータを指定しなければ、Object型のストリームとして扱われる。
<R> Stream<R> map(Function<? super T,? extends R> mapper)
mapperの戻り値をストリームとして返す。
集合データ内の各要素を変換するメソッド。
マップ操作では、1つの要素に対する操作で、1つの要素が返される。
import java.util.Arrays;
public class MapSample {
public static void main(Stringl] args) {
String[] fruits = {"apple", "orange", "banana"};
Arrays.stream(fruits)
.map(f -> f.toUpperCase())
.forEach(System.out::println);
}
}
APPLE
ORANGE
BANANA
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class MapSample {
public static void main(Stringl] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<String> result =
list.stream().map(n -> String.valueOf(n));
}
}
1
2
3
4
5
List<String> nameList = Arrays.asList("Tanaka", "Suzuki", "Takahashi");
Stream<Integer> stream = nameList.stream().map(x -> x.length());
System.out.println(stream.collect(Collectors.toList()));
[6, 6, 9]
関数型インタフェースFunctionは、引数と戻り値を別の型で指定できる。
IntStream mapToInt(ToIntFunction<? super T> mapper)
文字列を数値に変換。中間操作。
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
イメージとしてはコレクションを含んだstreamを各値の一連のストリームにするメソッド。
フラットマップ操作とは、各要素を何らかのロジックで分解したり増幅したりするための操作です。従ってフラットマップ操作では、1つの要素に対する操作で、複数の要素が返される。
List<String> nameList = Arrays.asList("Tanaka", "Suzuki", "Takahashi");
Stream<Object> stream = nameList.stream().flatMap(x -> Stream.of(x, x.length()));
System.out.println((stream.collect(Collectors.toList())));
[Tanaka, 6, Suzuki, 6, Takahashi, 9]
IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)
イメージとしてはコレクションを含んだstreamを各値の一連のストリームをIntStreamに変換。
Stream<T> distinct()
重複を除いたストリームを返す。
import java.util.Arrays;
import java.util.List;
public class DistinctSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("A","B","C","A");
list.stream()
.distinct()
.forEach(System.out::println);
}
}
A
B
C
public class Value {
private String data;
public Value(String data) {
this.data = data;
}
@Override
public int hashCode() {
return 100;
}
@Override
public boolean equals(Object obj) {
return true;
}
}
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main (String[] args) {
List<Value> list = Arrays.asList(
new Value("A"),
new Value("B"),
new Value("C"),
new Value("A")
);
long size = list.stream().distinct().count();
System.out.println(size);
}
}
1
重複しているかどうかはequalsメソッドの結果がtrueになるかどうかで判定。
インスタンスが異なってもequalsメソッドによって「同値である」と判定される場合には、重複していると見なされて、取り除かれる。
Stream<T> sorted()
自然順序に並べてストリームを返す。ただしストリームの要素がComparableでない場合、例外がスローされる可能性がある。
import java.util.Arrays;
import java.util.List;
public class SortSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "C", "A");
list.stream()
.sorted()
.forEach(System.out::println);
}
}
A
A
B
C
Stream<T> sorted(Comparator<? super T> comparator)
こっちはComparator型のインスタンスを直接引数に取っている。つまりcomparatorに従って並べ替えたストリームを返す。
class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@Override
public String toString() {
return this.name;
}
}
import java.util.Arrays;
import java.util.List;
public class SortSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item("A"),
new Item("C"),
new Item("B")
);
list.stream()
.sorted((a, b) -> a.getName().compareTo(b.getName()))
.forEach(System.out::println);
}
}
A
B
C
Stream<T> peek(Consumer<? super T> action)
ストリーム・パイプラインの途中でどのような状態になっているかを確認したいときに使用。
import java.util.Arrays;
import java.util.List;
public class PeekSample {
public static void main(Stringl] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream()
.map(x -> x * 3)
.peek(x -> {
System.out.println("debug:" + x);
})
.filter(x -> x % 2 == 0)
.forEach(x -> {
System.out.println("value:" + x);
});
}
}
debug:3
debug:6
value:6
debug:9
debug:12
value:12
debug:15
Stream<T> limit(long maxSize)
maxSize個までのストリームを返す。
import java.util.Arrays;
import java.util.List;
public class LimitSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream()
.limit(5)
.forEach(System.out::println);
}
}
1
2
3
4
5
Stream<T> skip(long n)
nだけ要素を飛ばしたストリームを返す。
import java.util.Arrays;
import java.util.List;
public class SkipSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream()
.skip(5)
.forEach(System.out::println);
}
}
6
7
8
9
10
終端操作のメソッド
collect(Collector<? super T,A,R> collector)
collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
ストリーム内の要素の集合を戻す。
List<String> list = Stream.of("A", "B", "C").collect(Collectors.toList());
System.out.println(list);
A, B, C
void forEach(Consumer<? super T> action)
ストリームの各要素に対して処理を行う。
List.of("1", "2", "3").forEach(x -> System.out.println(x));
java.util.function.Consumerは、引数を受け取り、結果を戻さない処理。
import java.util.List;
public class ForEachSample {
public static void main(String[] args) {
List<String> list = List.of("Alice", "Bob", "Charlie");
list.stream().forEach(name -> System.out.println("Hello, " + name));
}
}
Hello, Alice
Hello, Bob
Hello, Charlie
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class ForEachSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "F");
Stream<String> stream = list.stream();
stream.forEach(x -> {
System.out.println(x);
});
}
}
ABCDE
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
public class ForEachSample {
public static void main (String[] args) {
Set<String> set = new HashSet<>();
set.add("E");
set.add("D");
set.add("C");
set.add("B");
set.add("A");
Stream<String> stream = set.stream();
// ハッシュコード順に出力
stream.forEach(System.out::println);
}
}
ABCDE
void forEachOrdered(Consumer<? super T> action)
定義された実行順に従い、ストリームの各要素に対して処理を行う。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class ForEachOrderedlSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", 'C", 'D", "F");
Stream<String> stream = list.parallelStream();
stream.forEachOrdered(System.out::println); // 実行する度に結果が同じ
}
}
A
B
C
D
F
default Stream<E> parallelStream()
並列ストリーム
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class ParallelSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", 'C", 'D", "F");
Stream<String> stream = list.parallelStream();
stream.forEach(System.out::println); // 実行する度に結果が異なる
}
}
boolean anyMatch(Predicate<? super T> predicate)
ストリームの各要素のうち、一つでも条件を満たせばtrue
boolean result = Stream.of(1,2,3,4).anyMatch(p -> p == 2);
System.out.println(result);
「true」が一つだけ出力。
boolean allMatch(Predicate<? super T> predicate)
全てが条件を満たせばtrue
boolean noneMatch(Predicate<? super T> predicate)
全てが条件を満たさないのであればtrue
Optional<T> findFirst()
ストリームの最初の要素を返す。Optionalについては後述
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
public class FindFirstSample {
public static void main(String[] args) {
String[] array = {"A", "B", "C"}
Stream<String> stream = Arrays.stream(array);
Optional<String> optional = stream.findFirst();
optional.ifPresent(System.out::println);
}
}
A
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
public class FindFirstSample {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4, 5);
list.parallelStream()
.findFirst()
.ifPresent(System.out::println);
}
}
1
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class FindFirstSample {
public static void main(String[] args) {
Predicate<Integer> p = (num) -> {
boolean result = num % 2 == 0;
System.out.println(num + ":" + result);
return result;
};
List<Integer> list = List.of(1, 2, 3, 4, 5);
list.parallelStream()
.filter(p)
.findFirst()
.ifPresent(System.out::println);
}
}
フィルタリングの順番は毎回同じ結果にならない
findFirstメソッドが戻すのは、条件によって絞られたストリームの先頭にある2
1: false
2: true
3: false
5: false
4: true
2
Optional<T> findAny()
順序は保証されていないが(ランダム)、最初に見つけたストリームの要素を返す。
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
public class FindAnySample {
public static void main(String[] args) {
String[] array = {"A", "B", "C"}
Stream<String> stream = Arrays.stream(array);
Optional<String> optional = stream.findAny();
optional.ifPresent(System.out::println);
}
}
A
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
public class FindAnySample {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4, 5);
list.parallelStream()
.findAny()
.ifPresent(System.out::println);
}
}
ランダム出力
Optional<T> min(Comparator<? super T> comparator)
comparatorに従って、ストリーム要素中の最小値を返す。
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class MinSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(98, 99, 96, 95, 97);
Optional<Integer> result =
list.stream().min((a, b) -> {
if (a == b) return 0;
if (a < b) return -1;
return 1;
});
result.ifPresent(System.out::println);
}
}
95
Optional<T> max(Comparator<? super T> comparator)
comparatorに従って、ストリーム要素中の最大値を返す。
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class MaxSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(98, 99, 96, 95, 97);
Optional<Integer> result =
list.stream().max((a, b) -> {
if (a == b) return 0;
if (a < b) return -1;
return 1;
});
result.ifPresent(System.out::println);
}
}
99
import java.util.Optional;
public class MaxSample {
public static void main(String[] args) {
List<String> list = Arrays.asList("B", "A", "D", "C");
Optional<String> result =
list.stream().max((a, b) -> a.compareTo(b));
result.ifPresent(System.out::println);
}
}
D
T reduce(T identity, BinaryOperator<T> accumulator)
(初期値)identityから引数を順番に二つとって引数と同じ型を返す
accumulator(BinaryOperator)の処理を行う
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class ReduceSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer result = list.stream().reduce(10, (a, b) -> a + b)
System.out.println(result);
}
}
25
Optional<T> reduce(BinaryOperator<T> accumulator)
ストリームから引数を二つとって、引数と同じ型の結果を返す。
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class ReduceSample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = list.stream().reduce((a, b) -> a + b)
result.ifPresent(System.out::println);
}
}
15
インタフェースIntStream
IntStream limit(long maxSize)
maxSize個までのストリームを返す。
中間操作。
Stream<U> mapToObj(IntFunction<? extends U> mapper)
指定された関数をこのストリームの要素に適用した結果から構成される、オブジェクト値のStreamを返す。
中間操作。
OptionalDouble average()
要素の平均を求める。OptionalDoubleまたは空のOptional (このストリームが空の場合)を返す。終端操作。
long count()
ストリームの要素の個数を返す。
終端操作。
IntStream range(int startInclusive, int endExclusive)
startInclusive(含む)からendExclusive(含まない)の範囲でステップ1でインクリメントした値を含む、順序付けされた順次IntStreamを返します。
public static void main(String[] args) {
int max = java.util.stream.IntStream.range(1, 100).max().getAsInt();
System.out.println(max);
}
99
IntStream rangeClosed(int startInclusive, int endInclusive)
startInclusive(含む)からendInclusive(含む)の範囲でステップ1でインクリメントした値を含む、順序付けされた順次IntStreamを返す。
public static void main(String[] args) {
int max = java.util.stream.IntStream.rangeClosed(1, 100).max().getAsInt();
System.out.println(max);
}
100
static IntStream iterate(int seed, IntUnaryOperator f)
第1引数に初期値を与え、最初はその初期値を用いて以降の中間操作 or 終端操作を行い、2回目は初期値を引数に取って第2引数の関数が呼ばれ、戻り値を用いて以降の中間操作 or 終端操作を行う。
無限順次StreamなのでStream#limit を用いて要素数を制限する必要があります。limit を忘れると例外が発生せず無限ループになる。
var r = new Random();
IntStream stream = IntStream.iterate(0, a -> a + 1);
stream.limit(5)
.mapToObj(x -> x + ",")
.forEach(System.out::println);
0,1,2,3,4
その他
Stream<T> generate(Supplier<? extends T> s)
引数のラムダ式が戻す値を含むランダムな整数のストリームを生成するメソッド。
var r = new Random();
IntStream.generate(r::nextInt)
.limit(10)
.forEach(System.out::println);
java.util.RandomクラスのnextIntメソッドは、乱数を生成する。
staticメソッドでなく、インスタンスメソッドである。
<T> Stream<T> iterate(T seed, UnaryOperator<T> f)
IntStream、LongStream、DoubleStream にも同様のメソッドがある。
java.util.stream.Collector
途中経過を保持するオブジェクト
Collectorの抽象メソッド
- supplier
- accumulator
- finisher
- combiner
- characteristics
java.util.stream.Collectorインタフェースのうち実際に行いたい処理を記述するためのものは、「accumulatorメソッド」
toList
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorsSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
List<Item> books =
list.stream()
.filter(item -> item.getType() == ItemType.BOOK)
.collect(Collectors.toList());
books.forEach(System.out::println);
}
}
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
toSet
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorsSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
Set<Item> books =
list.stream()
.filter(item -> item.getType() == ItemType.BOOK)
.collect(Collectors.toSet());
books.forEach(System.out::println);
}
}
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
toMap
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CollectorsSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
Map<String, Item> map =
list.stream().collect(Collectors.toMap(
Item::getName,
item -> item));
map.keySet().stream().forEach(System.out::println);
}
}
Java
Test
Software
Lambda
groupingBy
java.util.Map型の戻り値を戻す
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupingSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
Map<ItemType, List<item>> group =
list.stream().collect(
Collectors.groupingBy(Item::getType));
System.out.println(group);
}
}
{
BOOK=[
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
],
MAGAZINE=[
Item [id=3, type=MAGAZINE, name=Software, price=980]
Item [id=4, type=MAGAZINE, name=Test, price=1280]
]
}
summingInt
値の種類ごとにグルーピング。
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SummingIntSample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
Map<ItemType, Integer> group =
list.stream().collect(
Collectors.groupingBy(
Item::getType,
Collectors.summingInt(Item::getPrice)));
System.out.println(group);
}
}
{BOOK=4960, MAGAZINE=2260}
partitioningBy
条件を指定して、その条件に合致したかどうかでグループを分けることができる。
java.util.Map型の戻り値を戻す。
返されるMapには、常にfalseとtrueキーの両方のマッピングが含まれている。
public enum ItemType {
BOOK, MAGAZINE, DVD
}
public class Item {
private int id;
private ItemType type;
private String name;
private int price;
public Item(int id, ItemType type, String name, int price) {
super();
this.id = id;
this.type = type;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public ItemType getType() {
return type;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "Item [id=" + id + ", type=" + type
+ ", name=" + name + ", price=" + price + "]";
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class PartitioningBySample {
public static void main(String[] args) {
List<Item> list = Arrays.asList(
new Item(1, ItemType.BOOK, "Java", 1980),
new Item(2, ItemType.BOOK, "Lambda", 2980),
new Item(3, ItemType.MAGAZINE, "Software", 980),
new Item(4, ItemType.MAGAZINE, "Test", 1280)
);
Map<Boolean, List<Item>> map =
list.stream().collect(
Collectors.partitioningBy(
item -> item.getPrice() > 1000));
System.out.println(map);
}
}
false=[
Item [id=3, type=MAGAZINE, name=Software, price=980]
],
true=[
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
Item [id=4, type=MAGAZINE, name=Test, price=1280]
]
java.util.stream.Collectors
<T> Collector<T,?,Double> averagingDouble(ToDoubleFunction<? super T> mapper)
ストリームの要素をdouble型に変換し、平均を求める。
double a = list.stream()
.collect(Collectors.);