web-dev-qa-db-ja.com

Stream :: flatMapのこの使用法が間違っているのはなぜですか?

このようにStream :: flatMapを使用できると期待していました

public static List<String> duplicate(String s) {

    List<String> l = new ArrayList<String>();
    l.add(s);
    l.add(s);

    return l;
}


listOfStrings.stream().flatMap(str -> duplicate(str)).collect(Collectors.toList());

しかし、次のコンパイラエラーが発生します

Test.Java:25:エラー:互換性のないタイプ:タイプ変数を推測できませんR listOfStrings.stream()。flatMap(str-> duplicate(str))。collect(Collectors.toList());

(引数の不一致。ラムダ式リストの戻り値の型が正しくないため、ストリームに変換できません)
ここで、R、Tは型変数です。RはメソッドflatMap(Function>)で宣言されたオブジェクトを拡張しますTはインターフェイスStreamで宣言されたオブジェクトを拡張します

In scala私は同等だと信じていることをすることができます

scala> List(1,2,3).flatMap(duplicate(_))
res0: List[Int] = List(1, 1, 2, 2, 3, 3)

これがJavaでのflatMapの有効な使用法ではないのはなぜですか?

17
Simon

flatMap のラムダ式はStreamを返す必要があります。これは、Function<? super T, ? extends Stream<? extends R>>型のflatMapの引数からわかります。

次のコードはコンパイルされ、正常に実行されます。

listOfStrings.stream()
             .flatMap(str -> duplicate(str).stream()) // note the .stream() here
             .collect(Collectors.toList());

ラムダ式str -> duplicate(str).stream()のタイプはFunction<String, Stream<String>>であるためです。

23
Tunaki

ストリーム内の各オブジェクトを複数回複製する場合は、ArrayListを追加してメモリを浪費する必要はありません。より短く、より速い選択肢がいくつかあります。

  • Stream.generateを使用して新しいストリームを生成し、それを制限します。

    listOfStrings.stream()
                 .flatMap(str -> Stream.generate(() -> str).limit(2))
                 .collect(Collectors.toList());
    
  • IntStream.rangeを介して一連の数値を生成し、それらを同じ文字列にマップします。

    listOfStrings.stream()
                 .flatMap(str -> IntStream.range(0, 2).mapToObj(i -> str))
                 .collect(Collectors.toList());
    
  • 古き良きCollections.nCopiesを使用する:

    listOfStrings.stream()
                 .flatMap(str -> Collections.nCopies(2, str).stream())
                 .collect(Collectors.toList());
    

常に正確に2回複製することが確実な場合は、最短の方法があります。

listOfStrings.stream()
             .flatMap(str -> Stream.of(str, str))
             .collect(Collectors.toList());
6
Tagir Valeev