为什么Collection <T>实现Stream <T>?

Vit*_*liy 7 java lambda api-design java-8

这是关于API设计的问题.在C#中添加扩展方法时,获取IEnumerable所有在所有集合上直接使用lambda表达式的方法.

随着Java中lambdas和默认方法的出现,我希望Collection能够实现Stream并为其所有方法提供默认实现.这样,我们就不需要调用stream()它来利用它提供的功率.

图书馆建筑师选择不太方便的方法的原因是什么?

Joh*_*ica 8

来自Maurice Naftalin的Lambda FAQ:

为什么Stream操作没有直接在Collection上定义?

的API暴露的方法,如早期的草稿filter,mapreduceCollectionIterable.但是,用户使用此设计的体验导致将"流"方法更正式地分离为他们自己的抽象.原因包括:

  • 在方法CollectionremoveAll让就地修改,而相比之下,新方法,这在本质上更多的功能.在同一抽象上混合两种不同的方法迫使用户跟踪哪些是哪种.例如,给出声明

    Collection strings;
    
    Run Code Online (Sandbox Code Playgroud)

    两个非常相似的方法调用

    strings.removeAll(s -> s.length() == 0);
    strings.filter(s -> s.length() == 0);          // not supported in the current API
    
    Run Code Online (Sandbox Code Playgroud)

    会有惊人的不同结果; 第一个将从String集合中删除所有空对象,而第二个将返回包含所有非空Strings 的流,而对集合没有影响.

    相反,当前设计确保只能过滤明确获得的流:

    strings.stream().filter(s.length() == 0)...;
    
    Run Code Online (Sandbox Code Playgroud)

    省略号表示进一步的流操作,以终止操作结束.这使读者对滤波器的作用有了更清晰的直觉;

  • 随着懒惰方法的添加Collection,用户感到困惑的是一种感知但错误的需要来推断该集合是处于"懒惰模式"还是"急切模式".与其Collection为新功能和不同功能增加负担,提供Stream具有新功能的视图更为清晰;

  • 添加的方法越多Collection,与现有第三方实现名称冲突的可能性就越大.通过仅添加一些方法(stream,parallel),大大减少了冲突的机会;

  • 访问并行视图仍需要视图转换; 顺序流和并行流视图之间的不对称是不自然的.比较,例如

    coll.filter(...).map(...).reduce(...);
    
    Run Code Online (Sandbox Code Playgroud)

    coll.parallel().filter(...).map(...).reduce(...);
    
    Run Code Online (Sandbox Code Playgroud)

    这种不对称性在API文档中尤为明显,其中Collection有许多新方法可以生成顺序流,但只有一种方法可以生成并行流,这些流将具有与之相同的方法Collection.StreamOps例如,将这些因素分解为一个单独的界面无济于事; 这将是,直觉相反,需要由双方执行StreamCollection;

  • 对观点的统一处理也为将来的其他观点留下了空间.