【问题标题】:Typing a list List<String> inside a reduce accumulator not compiling在减少累加器中键入列表 List<String> 不编译
【发布时间】:2021-06-25 09:01:13
【问题描述】:

我在输入 reduce 操作的累加器时遇到问题,原因有两个。

首先,我从这篇文章中了解到,在使用(identity, accumulator)签名时,如果返回类型与被归约集合内部的不同,则需要有一个显式的@987654322 @ 帮助编译器。然而,返回类型总是由我们传递的身份明确表示!为什么编译器不能自己推断出这也是一样的?

List<String> productNames =
    products.stream()
        .reduce(
            new ArrayList<>(), 
            (acc, elm) -> {
              List<String> newList = new ArrayList<>(acc);
              newList.add(elm.getName());
              return newList; // Won't compile!
            });

第二,当我尝试创建当前累积值的副本时,我必须显式传递具体类型而不仅仅是接口,就像我们通常使用列表所做的那样。

List<String> productNames =
    products.stream()
        .reduce(
            new ArrayList<>(),
            (acc, elm) -> {
              List<String> newList = new ArrayList<>(acc);   // Won't compile! needs ArrayList<String>
              newList.add(elm.getName());
              return newList;
            },
            (list1, list2) -> {
              ArrayList<String> newList = new ArrayList<>(list2);
              newList.addAll(list1);
              return newList;
            });

【问题讨论】:

  • 请添加编译错误。

标签: java types reduce


【解决方案1】:

在这种情况下,为了减少你应该使用方法&lt;U&gt; U reduce(U identity, BiFunction&lt;U, ? super T, U&gt; accumulator, BinaryOperator&lt;U&gt; combiner) 而不是T reduce(T identity, BinaryOperator&lt;T&gt; accumulator)

如果我们谈论第一个签名,U identityBiFunction&lt;U, ? super T, U&gt; 返回类型必须完全相同U 等ArrayList。我们可以将其实例化为身份,但不能将其实例化为 List。

List<String> productNames =
    products.stream()
            .reduce(new ArrayList<>(),
                    (acc, elm) -> {
                        ArrayList<String> newList = new ArrayList<>(acc);
                        newList.add(elm.getName());
                        return newList; 
                    },
                    (list1, list2) -> { list1.addAll(list2); return list1;});

附:通过收集更容易达到这个目标:

List<String> productNames =
    products.stream()
            .collect(ArrayList::new , 
                     (list, product) -> list.add(product.getName()), 
                     ArrayList::addAll);

或者你可以使用地图操作:

List<String> productNames =
    products.stream()
            .map(Product::getName)
            .collect(Collectors.toList())

【讨论】:

  • 感谢您提供了一个不错的替代实现!除了命名,你写list2,我想。你的意思是产品,因为 list.getName() 不存在!
  • @Radioreve 是的 name list2 令人困惑,我的意思是产品,对不起。
【解决方案2】:

一些同事在我发布后不久给了我两个答案,所以我会尝试这样解释。

second sn-p 无法编译,因为 reduce 试图根据给定的内容推断返回值。在这种情况下,标识是显式类型,ArrayList 因此 reduce 期望返回这个精确类型,而不是兄弟。因此,List&lt;String&gt; 过于宽泛。

对于第一种情况,reduce 类型中的泛型类型&lt;T&gt; 与Stream 中传递的类型相同。因此,当我们使用只有标识和累加器的基本形式时,Java 明确期望 T 与 Stream 中的类型相同。如果我们想偏离这个,我们必须传入第三个参数,combiner。

【讨论】:

    【解决方案3】:

    首先。签名是T reduce(T identity, BinaryOperator&lt;T&gt; accumulator),因此标识必须与您的流元素具有相同的类型。你的身份有ArrayList&lt;?&gt; 类型,你的流元素

    (acc, elm) -> {
         List<String> newList = new ArrayList<>(acc);
         newList.add(elm.getName());
    

    很可能是不同的类型。

    第二你的累加器函数也应该被修正,合并器函数可以被简化

    (list1, list2) -> {
        list2.addAll(list1);
        return list2;
    }
    

    【讨论】:

    • 你的意思是可以在组合器内改变列表但不能在累加器内改变列表吗?
    • 累加器和合并器都可以改变列表。
    猜你喜欢
    • 1970-01-01
    • 2015-06-04
    • 2018-01-23
    • 1970-01-01
    • 2019-10-02
    • 2022-01-08
    • 2019-08-26
    • 1970-01-01
    • 2017-01-12
    相关资源
    最近更新 更多