【问题标题】:Stream reduce operation using interface流式减少操作使用接口
【发布时间】:2018-06-15 10:42:33
【问题描述】:

我有以下结构

public interface ICommon{
   ICommon add(ICommon other);
}

public class Foo implements ICommon{
    ...

    ICommon add(ICommon other){
        return new Bar().add(other);
    }

}

public class Bar implements ICommon{
    ...

    ICommon add(ICommon other){
        ...
    }

}

作为复合模式的一部分。

我想使用流减少操作,但不知何故我不能强制类型推断接口。我正在使用这个。

List<Foo> list;
list.stream().reduce( new Foo(), (a,b) -> a.add(b));

我收到一个错误,ICommon 无法转换为 Foo。

我尝试强制强制转换参数但没有成功。

【问题讨论】:

    标签: java java-stream reduce


    【解决方案1】:

    reduce 的三参数版本允许在执行归约时更改元素类型:

    list.stream().reduce(new Foo(), ICommon::add, ICommon::add);
    

    虽然此处使用了对相同方法的引用,但第二个参数是带有 (ICommon,Foo) -&gt; ICommon 签名的函数 (BiFunction),而第三个参数是带有 (ICommon,ICommon) -&gt; ICommon 签名的函数 (BinaryOperator) .

    另一种选择是对现有 List 的类型进行类型安全更改:

    Collections.<ICommon>unmodifiableList(list).stream().reduce(new Foo(), ICommon::add);
    

    由于不可变列表可以保证返回实际元素类型的超类型的值,同时防止插入新元素,因此此包装器允许将元素类型更改为超类型。此外,由于流操作是只读操作,包装器将stream() 调用重定向到原始列表,只是将其作为超类型的流返回。所以直接使用list.stream()没有性能差异。

    【讨论】:

    • 这其实很有帮助。 reduce 的两个版本之间的并行流有区别吗?
    • 没有实际区别。对于三参数版本,实现通常使用第一个函数进行顺序部分评估,然后使用第二个函数合并这些结果。由于这些函数在语义上应该是等价的(在这里,它是对相同方法的引用),所以没有区别。双参数版本完全相同,只是使用提供的函数进行顺序部分评估和合并。可能通过在内部调用完全相同的实现方法。
    • 第二个选项是我第一次看到。我什至不知道这是可能的(我第一次看到这样传递的泛型类型)。你有参考Collections.&lt;ICommon&gt;unmodifiableList(list)
    • 这只是一个显式类型的调用,如in the tutorial 所示(比较最后的两个变体)。方法本身就是Collections.unmodifiableList(…)。它也适用于隐式类型,例如在作业中:List&lt;ICommon&gt; newList = Collections.unmodifiableList(list);
    • 我一直使用隐式赋值。谢谢!
    【解决方案2】:

    这里的问题是您的List 使用Foo 进行参数化,但是由于add 调用,您的归约操作将使用ICommon 进行参数化。

    虽然所有Foos 都是ICommons,但并非所有ICommons 都是Foos。

    对您而言,最简单的方法是使用 ICommon 参数化您的 List,而不更改(可见)代码中的任何其他内容。

    类似:

    List<ICommon> list = [some list of Foos];
    list.stream().reduce( new Foo(), (a,b) -> a.add(b));
    

    【讨论】:

    • 该列表是用Foo 参数化的,因为我正在创建Foo 的流。我只是把它列为这个来提供一个最小的例子。谢谢你。这行得通。
    【解决方案3】:

    找到问题的解决方案。 reduce 操作有签名

    T reduce(T identity, BinaryOperator<T> accumulator);
    

    我所要做的就是转换成ICommon的流

    list.stream().map(x-> (ICommon) x).reduce( new Foo(), (a,b) -> a.add(b));
    

    【讨论】:

    • 不需要演员,list.stream().reduce(new Foo(), ICommon::add, ICommon::add);...
    猜你喜欢
    • 2017-10-28
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2016-09-21
    • 2022-01-21
    • 1970-01-01
    • 2021-06-08
    相关资源
    最近更新 更多