流使用接口减少操作

时间:2018-01-05 15:31:06

标签: 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 add(ICommon other){
        ...
    }

}

作为复合模式的一部分。

我想使用流reduce操作,但不知何故我不能强制对接口进行类型推断。我正在使用它。

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

我收到的错误是ICommon无法投放到Foo

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

3 个答案:

答案 0 :(得分:4)

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

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

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

类似的东西:

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

答案 1 :(得分:1)

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

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

我所要做的只是投射到ICommon

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

答案 2 :(得分:1)

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

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

虽然这里使用了对同一方法的引用,但第二个参数是带有BiFunction签名的函数((ICommon,Foo) -> ICommon),而第三个参数是函数(BinaryOperator(ICommon,ICommon) -> ICommon签名。

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

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

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