6️⃣

Java ストリームAPI

2024/07/08に公開

概要

「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