Java ストリームAPI
概要
「Java SE 11 Programmer II (1Z0-816-JPN) 試験」の出題範囲「Java ストリームAPI」の自己学習メモになります
ストリームAPI
ストリームAPIは、コレクション、配列、I/Oリソースなどのデー タ提供元となるデータソースをもとに、集計操作を行うAPIです。ストリームは、ある処理結果を次の処理のデータソース(入力)として渡すことができます。そのため、データソースをもとに様々な処 理を通じてデータを加工することができます。
List<String> list = Arrays.asList("bb", "aa", "cc");
//従来の実装例
for(int i = 0; i < list.size(); i++) {
String str = list.get(i).toUpperCase();
list.set(i, str);
}
Collections.sort(list);
for(String str : list){
System.out.print(str + " "));
}
System.out.println();
list = Arrays.asList("bb", "aa", "cc");
//ストリームAPIの利用例
list.stream().sorted().map(s -> s.toUpperCase()).forEach(
s -> System.out.print(s + " "));
- 問合せの対象となるデータソース : コレクション、配列、I/Oリ ソースなど
- 中間操作 : ストリームに対して処理を行った結果をストリーム で返す
- 終端操作 : 処理結果をデータとして返す
ストリームの種類と生成
Collectionインターフェースで提供
メソッド名 | 例 |
---|---|
default Stream<E> stream() | List<String> list= Arrays.asList(""a"",""b"", ""c""); Stream <String> stream=list.stream(); |
Arrays クラスで提供
メソッド名 | 説明 |
---|---|
static <T> Stream<T> stream(TD] array) | String[] ary = "a"", "b"",""c""'}; Stream <String> stream = Arrays.stream (ary): |
static IntStream stream(int[] array) | int[] ary = {1,2,3}; IntStream stream = Arrays.stream(ary): |
Stream インタフェースで提供
メソッド名 | 説明 |
---|---|
static <T> Stream<T> of(T t) | Stream <String> stream = Stream.of("abc"); |
static <T> Stream<T> of(T... values) | Stream <Long > stream = Stream.of(1L, 2L, 3L): |
static <T> Stream<T> empty() | Stream <String> stream = Stream.empty(); |
static <T> Stream<T> generate( Supplier<T> s) | Stream <String> stream = Stream.generate (() -> ""Java"); |
IntStream インタフェースで提供
メソッド名 | 説明 |
---|---|
static IntStream of(int... values) | IntStream stream = IntStream.of(1,2,3); |
static IntStream iterate(int seed,IntUnaryOperator f) | IntStream stream = IntStream.iterate(1, n-> n + 1); |
static IntStream iterate( int seed,IntPredicate hasNext, IntUnaryOperator next) | IntStream.iterate(1, n -> n <= 10, n-> n+1): |
static IntStream range(int startInclusive,int endExclusive) | IntStream stream = IntStream.range(1, 10); |
static IntStream rangeClosed(int startInclusive,int endInclusive) | IntStream stream = IntStream.rangeClosed(1, 10); |
ストリームに種類
インターフェース名 | 説明 |
---|---|
Stream<T> | 順次および並列の集約操作をサポートする汎用的なストリーム |
IntStream | 順次および並列の集約操作をサポートする int 値のストリーム。ただし、int の他、short byte char 型に使用可能 |
LongStream | 順次および並列の集約操作をサポートする long 値のストリーム |
DoubleStream | 順次および並列の集約操作をサポートする double 値のストリーム。 ただし、 double の他、 float 型に使用可能 |
終端操作
メソッド名 | 例 |
---|---|
boolean allMatch(Predicate<? super T> predicate) | すべての要素が指定された条件に一致するか どうかを返す。 一致しているか、ストリームが空の場合はtrue、それ以外の場合は false |
boolean anyMatch(Predicate<? super T> predicate) | いずれかの要素が指定された条件に一致する かどうかを返す。 存在する場合は true、 そう でない場合は false |
boolean noneMatch(Predicate<? super T> predicate) | どの要素も指定された条件に一致しないか、 ストリームが空の場合は true、 それ以外の場 合は false を返す |
<R.A> R collect(Collector<? super T.A.R> collector) | 要素に対する可変リダクション操作を実行する |
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator,BiConsumer<R,R> combiner) | 要素に対する可変リダクション操作を実行する |
long count() | 要素の個数を返す |
Optional<T> findAny() | いずれかの要素を返す。 ストリームが空の場 合は空の Optional を返す |
Optional<T> findFirst() | 最初の要素を返す。 ストリームが空の場合は 空の Optional を返す |
void forEach(Consumer<? super T> action) | 各要素に対して指定されたアクションを実行する |
Optional<T> min(Comparator<? super T comparator) | 指定されたComparatorに従って最小要素を返す。 ストリームが空の場合は空の Optionalを返す |
Optional<T> max(Comparator<? super T> comparator) T reduce(T identity.BinaryOperator<T> accumulator) | 指定されたComparatorに従って最大要 素を返す。ストリームが空の場合は空のOptionalを返す |
T reduce(T identity, BinaryOperator<T> accumulator) | 元の値と結合的な累積関数を使ってこのストリームの要素に対してリダクションを実行し、リデュースされた値を返す |
Object[] toArray() | 要素を含む配列を返す |
<A> A[] toArray(IntFunction<A[]> generator) | 指定された型と長さをもつ新しい配列を生成する関数を引数に指定し、配列を返す |
終端操作の実装例
allMatch()、anyMatch()、noneMatch()メソッド
List<String> data1 = Arrays.asList("mana", "naoki", "ryo");
boolean result1 = data1.stream().allMatch(s -> s.length() >= 3);
boolean result2 = data1.stream().anyMatch(s -> s.length() == 4);
boolean result3 = data1.stream().noneMatch(s -> s.length() == 4);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
実行結果
true
true
false
count()、forEach()メソッド
long result1 = Stream.of("a", "b", "c").count();
System.out.println(result1);
Stream<String> stream1 = Stream.of("a", "b", "c");
stream1.forEach(System.out::print);
実行結果
3
abc
reduce()メソッド
Stream<Integer> stream = Stream.of(10, 20, 30);
int result = stream.reduce(0, (a, b) -> a + b);
System.out.println(result);
実行結果
60
構文
構文1:T reduce(T identity, BinaryOperator<T> accumulator)
構文2:Optional<T> reduce(BinaryOperator<T> accumulator)
構文3:<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner)
IntStreamで提供
int reduce(int identity, IntBinaryOperator op)
DoubleStreamで提供
double reduce(double identity, DoubleBinaryOperator op)
LongStreamで提供
long reduce(long identity, LongBinaryOperator op)
toArray()メソッド
Streamインタフェースで提供
構文1 : Object[] toArray()
構文2 : <A> A[] toArray(IntFunction<A[]> generator)
IntStreamインタフェースで提供
構文3 : int[] toArray()
Optionalクラス
OptionalクラスはSE 8から追加されたクラスで、実体は1つの値 を保持しているクラスです。特徴として、Optionalクラスの各メソッ ドは、保持している値が存在するか否かによって処理が異なります。
Optionalクラスの主なメソッド
メソッド名 | 説明 |
---|---|
static <T> Optional<T> empty() | 空の Optionalインスタンスを返す。このOptionalには値は存在しない |
static <T> Optional<T> of(T value) | 引数で指定された非null値を含む Optional を返す |
T get() | 値が存在する場合は値を返し、 それ以外の場合は NoSuchElementException をスローする |
boolean isPresent() | 値が存在する場合はtrueを返し、それ以外の場合はfalseを返す |
boolean isEmpty() | 値が存在しない場合はtrueを返し、それ以外の場合はfalseを返す |
void ifPresent(Consumer<? super T> consumer) | 値が存在する場合は指定されたコンシューマをその値で呼び出し、それ以外の場合は何も行わない |
T orElse(T other) | 値が存在する場合は値を返し、それ以外の場合はotherを返す |
T orElseGet(Supplier<? extends T> other) | 値が存在する場合は値を返し、それ以外の場合はサ プライヤを呼び出し、 その呼び出しの結果を返す |
<X extends Throwable> T orElse Throw(Supplier<? extends X> exceptionSupplier) throws X extends Throwable | 値が存在する場合は値を返し、それ以外の場合は 指定されたサプライヤによって作成された例外をス ローする |
Optionalクラスのget()とisPresent()メソッド
Optional<Integer> op1 = Optional.of(10);
Optional<Integer> op2 = Optional.empty();
//System.out.println("op2.get() : " + op2.get());
System.out.println("op1.get() : " + op1.get());
System.out.println("op1.isPresent() : " + op1.isPresent());
System.out.println("op2.isPresent() : " + op2.isPresent());
System.out.println("op1.isEmpty() : " + op1.isEmpty());
System.out.println("op2.isEmpty() : " + op2.isEmpty());
実行結果
op1.get() : 10
op1.isPresent() : true
op2.isPresent() : false
op1.isEmpty() : false
op2.isEmpty() : true
max()メソッド
List<String> data = Arrays.asList("aaa", "bb", "c");
Optional<String> result1 =
data.stream()
.max(Comparator.naturalOrder());
Optional<String> result2 =
data.stream()
.max((d1, d2) -> d1.length() - d2.length());
result1.ifPresent(System.out::println);
//System.out.println(result1.get());
result2.ifPresent(System.out::println);
//System.out.println(result2.get());
実行結果
c
aaa
findFirst()、findAny()メソッド
List<String> data = Arrays.asList("c", "a");
Optional<String> result1 = data.stream().findFirst();
Optional<String> result2 = data.stream().findAny();
System.out.println("result1 : " + result1.get());
System.out.println("result2 : " + result2.get());
Stream<String> stream = Stream.empty();
Optional<String> result3 = stream.findFirst();
//System.out.println("result3 : " + result3.get());
result3.ifPresent(r -> System.out.println("result3 : " + r));
IntStream intStream = IntStream.of(10, 20, 30);
OptionalInt result4 = intStream.findFirst();
//System.out.println("result4 : " + result4.get());
System.out.println("result4 : " + result4.getAsInt());
実行結果
result1 : c
result2 : c
result4 : 10
戻り値の違い
インターフェース名 | 戻り値 | メソッド |
---|---|---|
Stream | Optional<T> | |
IntStream | OptionalDouble | average |
IntStream | OptionalInt | findAny, findFirst, max, min |
IntStream | int | sum |
OptionalクラスのorElse()、orElseGet()、 orElseThrow()メソッド
Stream<Double> stream = Stream.empty();
Optional<Double> result = stream.findFirst();
//System.out.println(result.get());
System.out.println(result.orElse(0.0));
System.out.println(result.orElseGet(() -> Math.random()));
System.out.println(result.orElseThrow(
IllegalArgumentException::new));
//System.out.println(result.orElseThrow(
//() -> new IllegalArgumentException()));
実行結果
0.0
0.6560057821880242
Exception in thread "main" java.lang.IllegalArgumentException
at java.base/java.util.Optional.orElseThrow(Optional.java:408)
at Main.main(Main.java:11)
中間操作
中間操作の主なメソッド
メソッド名 | 説明 |
---|---|
Stream<T> filter (Predicate<? super T> predicate) | 指定された条件に一致するものから構成されるストリームを返す |
Stream<T> distinct() | 重複を除いた要素から構成されるストリームを返す |
Stream<T> limit(long maxSize) | maxSize以内の長さに切り詰めた結果から構成され るストリームを返す |
Stream<T> skip (long n) | 先頭からn個の要素を破棄した残りの要素で構成されるストリームを返す |
<R> Stream<R> map(Function<? super T,? extends R> mapper) | 指定された関数を適用した結果から構成されるストリームを返す |
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) | 指定された関数を適用した複数の結果から構成される1つのストリームを返す |
Stream<T> sorted() | 自然順序に従ってソートした結果から構成されるストリームを返す |
Stream<T> sorted(Comparator<? super T comparator) | 指定された Comparatorに従ってソートした結果 から構成されるストリームを返す |
Stream<T> peek (Consumer<? super T> action) | このストリームの要素から成るストリームを返す。 要素がパイプラインを通過する際にその内容を確認するようなデバッグとして使用する |
中間操作の実装例
filter()、distinct()メソッド
Stream<String> stream1 = Stream.of("ami", "naoki", "akko");
stream1.filter(s -> s.startsWith("a"))
.forEach(x -> System.out.print(x + " "));
System.out.println();
Stream<String> stream2 = Stream.of("", "naoki", "akko");
stream2.filter(Predicate.not(s -> s.isEmpty()))
.forEach(x -> System.out.print(x + " "));
System.out.println();
Stream<String> stream3 = Stream.of("ami", "naoki", "akko", "ami");
stream3.distinct()
.forEach(x -> System.out.print(x + " "));
実行結果
ami akko
naoki akko
ami naoki akko
limit()、skip()メソッド
IntStream.iterate(1, n -> n + 1)
.limit(10L)
.forEach(x -> System.out.print(x + " "));
System.out.println();
IntStream.rangeClosed(1, 10)
.skip(5L)
.forEach(x -> System.out.print(x + " "));
System.out.println();
IntStream.iterate(1, n -> n + 1)
.skip(100L)
.limit(5L)
.forEach(x -> System.out.print(x + " "));
System.out.println();
Stream<String> stream = Stream.generate(() -> "Java");
stream.limit(3L)
.forEach(x -> System.out.print(x + " "));
実行結果
1 2 3 4 5 6 7 8 9 10
6 7 8 9 10
101 102 103 104 105
Java Java Java
map()メソッド
// Stream<String>→Stream<String>
Stream<String> stream1a = Stream.of("naoki", "akko", "ami");
Stream<String> stream1b = stream1a.map(s -> s.toUpperCase());
stream1b.forEach(x -> System.out.print(x + " "));
System.out.println();
// Stream<String>→Stream<Integer>
Stream<String> stream2s = Stream.of("naoki", "akko", "ami");
Stream<Integer> stream2i = stream2s.map(s -> s.length());
stream2i.forEach(x -> System.out.print(x + " "));
System.out.println();
// IntStream→IntStream
IntStream stream3a = IntStream.of(1, 2, 3);
IntStream stream3b = stream3a.map(n -> n * 10);
stream3b.forEach(x -> System.out.print(x + " "));
実行結果
NAOKI AKKO AMI
5 4 3
10 20 30
flatMap()メソッド
List<Integer> data1 = Arrays.asList(10);
List<Integer> data2 = Arrays.asList(20, 30);
List<Integer> data3 = Arrays.asList(40, 50, 60);
List<List<Integer>> dataList =
Arrays.asList(data1, data2, data3);
//map()を使用した場合
dataList.stream()
.map(data -> data.stream())
.forEach(l -> {
l.forEach(x -> System.out.println(x + " "));});
System.out.println();
// flatMap()を使用した場合
dataList.stream()
.flatMap(data -> data.stream())
.forEach(x -> System.out.print(x + " "));
実行結果
10 20 30 40 50 60
10 20 30 40 50 60
sorted()メソッド
Stream.of("naoki", "akko", "ami")
.sorted()
.forEach(x -> System.out.print(x + " "));
System.out.println();
Stream.of("naoki", "akko", "ami")
.sorted(Comparator.reverseOrder())
.forEach(x -> System.out.print(x + " "));
実行結果
akko ami naoki
naoki ami akko
peek()メソッド
List<String> list =
Stream.of("one", "three", "two", "three", "four")
.filter(s -> s.length() > 3)
.peek(e -> System.out.println("After the filter : " + e))
.distinct()
.peek(e -> System.out.println("After the distinct : " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("After the map : " + e))
.collect(Collectors.toList());
実行結果
After the filter : three
After the distinct : three
After the map
After the filter
After the filter
After the distinct : four
After the map : FOUR
ストリームインタフェースの型変換
ストリームインタフェースの型変換を行うメソッド
インターフェース名 | Streamの生成 | DoubleStreamの生成 | IntStreamの生成 | LongStreamの生成 |
---|---|---|---|---|
Stream | map() | mapToDouble() | mapToInt() | mapToLong() |
DoubleStream | mapToObj() | map() | mapToInt() | mapToLong() |
IntStream | mapToObj() | mapToDouble() | map() | mapToLong() |
LongStream | mapToObj() | mapToDouble() | mapToInt() | map() |
型変化の使用例
元の型 | メソッド名 | 引数 | 変換後の型(戻り値) |
---|---|---|---|
Stream<String> | map | Function<? super T,? extends R> mapper | Stream<Integer> |
Stream<String> | mapTolnt | TolntFunction<? super T> mapper | IntStream |
Stream<Integer> | mapTolnt | TolntFunction<? super T> mapper | IntStream |
Stream<Integer> | map | Function<? super T,? extends R> mapper | Stream<String> |
IntStream | mapToObj | IntFunction<? extends U> mapper | Stream<String> |
IntStream | boxed | なし | Stream<Integer> |
boxed()メソッドを使用した型変換
- IntStream → Stream<Integer>
- DoubleStream → Stream<Double>
- LongStream → Stream<Long>
暗黙の変換を行うメソッド
メソッド名 | 説明 |
---|---|
LongStream asLongStream() | IntStreamインタフェースで提供。要素をlongに変換した結果から構成される LongStreamを返す |
DoubleStream asDoubleStream() | IntStreamインタフェースで提供。要素をdoubleに変換した結果から構成される DoubleStream を返す |
DoubleStream asDoubleStream() | LongStreamインタフェースで提供。要素をdoubleに変換した結果から構成されるDoubleStreamを返す |
collect()メソッドとCollectorsクラス
構文
構文1:<R,A> R collect(Collector<? super T,A,R> collector)
構文2:<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator,
BiConsumer<R,R> combiner)
構文:public interface Collector<T, A, R>
T:入力要素となるストリームの型
A:結果を生成する際に使用される型(通常は実装詳細として隠蔽される)
R:結果の型
Collectorsクラス
主なメソッド
メソッド名 | 説明 |
---|---|
static <T>Collector<T,?,List<T>> toList()) | 入力要素を List に蓄積する Collector を返す |
static Collector<CharSequence.?. String> joining() | 入力要素を検出順に連結して1つの String にす る Collector を返す |
static Collector<CharSequence,?, String> joining (CharSequence delimiter) | 入力要素を検出順に指定された区切り文字で区 切りながら連結する Collectorを返す |
static <T> Collector<T,?,Integer>summingInt(TolntFunction<? super T>mapper) | int 値関数を適用した結果の合計を生成する Collector を返す。 要素が存在しない場合、結果は0になる |
static <T> Collector<T,?,Double>averagingInt(TolntFunction<? super T>mapper) | int 値関数を適用した結果の算術平均を生成する Collector を返す。 要素が存在しない場合、 結果は0になる |
static <T> Collector<T,?,Set<T>> toSet() | 入力要素をSetに蓄積するCollectorを返す |
static <T,K,U>Collector<T,?,Map<K,U>> toMap( Function<? super T.? extendsK>key. Function<? super T.? extends U> value) | 入力要素をMapに蓄積する Collectorを返す |
static <T,K>Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T.?extends K> classifier) | 指定した関数に従って要素をグループ化し、結果をMapに格納して返す Collectorを返す |
static <T> Collector<T.?.Map< Boolean,List<T>>>partitioningBy(Predicate<?super T>predicate) | 指定した関数に従って要素をtrueもしくはfalseでグループ化し、結果を Map に格納して返すCollectorを返す |
static <T,U.A,R> Collector<T,?,R> mapping(Function<? super T.? extends U>mapper,Collector<? super U.A,R> downstream)static <T> Collector<T.?.Optional<T>>maxBy(Comparator<? super T> comparator) | 指定されたComparator に従ってOptional<T> として記述された最大要素を生成する Collectorを返す |
static <T> Collector<T,?,Optional<T>>minBy(Comparator<? super T>comparator) | 指定された Comparatorに従ってOptional<T> として記述された最小要素を生成するCollectorを返す |
toList()、joining()、summingInt()、 averagingInt()メソッド
// toList()メソッド
Stream<String> stream1 = Stream.of("naoki", "akko", "ami");
List<String> result1 = stream1.collect(Collectors.toList());
System.out.println(result1);
// joining()メソッド
Stream<String> stream2 = Stream.of("naoki", "akko", "ami");
String result2 = stream2.collect(Collectors.joining(" | "));
System.out.println(result2); 15.
// summingInt()メソッド
System.out.println(result3);
Stream<String> stream3 = Stream.of("naoki", "akko", "ami");
Integer result3 = stream3.collect(
Collectors.summingInt(t -> t.length()));
// averagingInt()メソッド
Stream<String> stream4 = Stream.of("naoki", "akko", "ami");
Double result4 = stream4.collect(
Collectors.averagingInt(t -> t.length()));
System.out.println(result4);
実行結果
[naoki, akko, ami]
naoki | akko | ami
12
4.0
toSet()、toMap()メソッド
// toSet()メソッド
Stream<String> stream1 = Stream.of("naoki", "akko", "ami");
Set<String> set =
stream1.collect(Collectors.toSet());
System.out.println(set);
// toMap()メソッド
Stream<String> stream2 = Stream.of("naoki", "akko", "ami");
Map<String, String> map =
stream2.collect(
Collectors.toMap(s -> s, String::toUpperCase));
System.out.println(map);
実行結果
[naoki, akko, ami]
{naoki=NAOKI, akko=AKKO, ami=AMI}
構文
構文1:
static <T,K,U> Collector<T,?,Map<K,U>> toMap(
Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper)
構文2:
static <T,K,U> Collector<T,?,Map<K,U>> toMap(
Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
構文3:
static <T,K,U,M extends Map<K,U>> Collector<T,?,M> toMap(
Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
groupingBy()メソッド
構文
構文1:
static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(
Function<? super T,? extends K> classifier)
構文2:
static <T,K,A,D> Collector<T,?,Map<K,D>> groupingBy(
Function<? super T,? extends K> classifier,
Collector<? super T,A,D> downstream)
構文3:
static <T,K,D,A,M extends Map<K,D>> Collector<T,?,M> groupingBy(
Function<? super T,? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T,A,D> downstream)
partitioningBy()メソッド
構文
構文1:
static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(
Predicate<? super T> predicate)
構文2:
static <T,D,A> Collector<T,?,Map<Boolean,D>> partitioningBy(
Predicate<? super T> predicate,
Collector<? super T,A,D> downstream)
mapping()メソッド
// map()メソッドの例
Stream<String> stream1 = Stream.of("naoki", "akko", "ami");
String result1 = stream1.map(s -> s.toUpperCase()).
collect(Collectors.joining(":"));
System.out.println(result1);
Stream<String> stream2 = Stream.of("naoki", "akko", "ami"); String result2 =
stream2.collect(
Collectors.mapping(s -> s.toUpperCase(),
Collectors.joining(":")));
System.out.println(result2);
実行結果
NAOKI:AKKO:AMI
NAOKI:AKKO:AMI
Discussion