为什么 Stream::flatMap 的这种用法是错误的?

2022-09-02 01:06:23

我希望能够像这样使用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: error: incompatible types: canfer type-variable(s) R listOfStrings.stream().flatMap(str -> duplicate(str)).collect(Collectors.toList());

(参数不匹配;lambda 表达式 List 中的错误返回类型无法转换为 Stream)
其中 R,T 是类型变量:R 扩展 在方法 flatMap(Function>) 中声明的对象 T 扩展在接口流中声明的对象

在scala中,我可以做我认为是等价的

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

为什么这不是java中flatMap的有效用法?


答案 1

flatMap 中的 lambda 表达式需要返回一个 ,这可以从其类型为 的参数中看出。StreamflatMapFunction<? super T, ? extends Stream<? extends R>>

以下代码将编译并正常运行:

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

因为 lambda 表达式的类型为 。str -> duplicate(str).stream()Function<String, Stream<String>>


答案 2

如果要多次复制流中的每个对象,则无需通过额外的 .有几种更短,更快的替代方案。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());
    

如果您确定始终重复两次,则有最短的选择:

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

推荐