代码之家  ›  专栏  ›  技术社区  ›  Radu Ionescu

使用接口的Stream reduce操作

  •  2
  • Radu Ionescu  · 技术社区  · 8 年前

    我有以下结构

    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));
    

    我发现一个错误 ICommon 无法转换为 Foo .

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

    3 回复  |  直到 8 年前
        1
  •  4
  •   Mena    8 年前

    这里的问题是 List 参数化为 Foo ,但还原操作将参数化为 ICommon 由于 add 调用。

    而所有 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));
    
        2
  •  1
  •   Holger    8 年前

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

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

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

    另一种选择是对现有 List s类型:

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

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

        3
  •  1
  •   Radu Ionescu    8 年前

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

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

    我所要做的就是 ICommon

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