Java 使用接口的流缩减操作

Java 使用接口的流缩减操作,java,java-stream,reduce,Java,Java Stream,Reduce,我有以下结构 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

我有以下结构

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){
        ...
    }

}
作为复合模式的一部分

我想使用streams reduce操作,但不知何故,我无法强制接口进行类型推断。我正在用这个

List<Foo> list;
list.stream().reduce( new Foo(), (a,b) -> a.add(b));
列表;
list.stream().reduce(newfoo(),(a,b)->a.add(b));
我收到一个错误,
ICommon
无法转换为
Foo


我曾试图强制转换参数,但没有成功

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

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

这里的问题是,您的
列表
是通过
Foo
参数化的,但是由于调用了
add
,您的缩减操作将通过
ICommon
参数化

虽然所有
Foo
s都是
ICommon
s,但并非所有
ICommon
s都是
Foo
s

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

比如:

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

有三个arg版本的
reduce
允许在执行reduce时更改元素类型:

list.stream().reduce(new Foo(), ICommon::add, ICommon::add);
虽然这里使用了对同一方法的引用,但第二个参数是具有
(ICommon,Foo)->ICommon
签名的函数(
BiFunction
),而第三个参数是具有
(ICommon,ICommon)->ICommon
签名的函数(
BinaryOperator

另一个选项是对现有
列表的类型进行类型安全更改:

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

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

自从我创建了
Foo
流以来,列表就用
Foo
参数化了。我只是把它列为这个例子来提供一个最低限度的例子。非常感谢。这是可行的。无需执行强制转换,
list.stream().reduce(new Foo(),ICommon::add,ICommon::add)…这实际上非常有用。
reduce
的两个版本之间的并行流是否存在差异?没有实际差异。对于三个arg版本,实现通常使用第一个函数进行顺序部分求值,然后使用第二个函数合并这些结果。因为这些函数在语义上应该是等价的(这里,它是对同一方法的引用),所以没有区别。这两个arg版本的功能完全相同,只需为两者使用提供的函数,即顺序部分求值和合并。可能是在内部调用完全相同的实现方法。第二个选项是我第一次看到它。我甚至不知道这是可能的(我第一次看到像这样传递泛型类型)。是否有对集合的引用。不可修改列表(list)
这只是一个显式类型的调用,如图所示(最后比较两个变量)。这个方法本身是公正的。它也适用于隐式类型,例如在赋值中:
List newList=Collections.unmodifiableList(List)我总是使用隐式赋值。非常感谢。
Collections.<ICommon>unmodifiableList(list).stream().reduce(new Foo(), ICommon::add);