在Stream和Collections API之间进行选择

CKi*_*ing 9 java collections java-8 java-stream

请考虑以下示例:在以下位置打印最大元素List:

List<Integer> list = Arrays.asList(1,4,3,9,7,4,8);           
list.stream().max(Comparator.naturalOrder()).ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

使用该Collections.max方法也可以实现相同的目标:

System.out.println(Collections.max(list));
Run Code Online (Sandbox Code Playgroud)

上面的代码不仅更短,而且阅读更清晰(在我看来).有一些类似的例子可以想到,例如使用binarySearchvs filter与之结合使用findAny.

我知道这 Stream可能是一个无限的管道,而不是Collection受JVM可用内存的限制.这将是我决定是使用API Stream还是使用CollectionsAPI的标准.是否还有其他原因选择StreamCollectionsAPI(如性能).更一般地说,这是选择Stream能够以更简洁的方式完成工作的旧API 的唯一理由吗?

Tag*_*eev 7

Stream API就像一把瑞士军刀:它可以让你通过有效地组合工具来完成相当复杂的操作.另一方面,如果你只需要一把螺丝刀,那么独立螺丝刀可能会更方便.Stream API包含许多内容(例如distinct,sorted原始操作等),否则需要您编写多行并引入中间变量/数据结构和无聊循环,从实际算法中吸引程序员的注意力.有时使用Stream API即使对于顺序代码也可以提高性能.例如,考虑一些旧的API:

class Group {
    private Map<String, User> users;

    public List<User> getUsers() {
        return new ArrayList<>(users.values());
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们希望返回该组的所有用户.API设计师决定返回一个List.但它可以通过各种方式在室外使用:

List<User> users = group.getUsers();
Collections.sort(users);
someOtherMethod(users.toArray(new User[users.size]));
Run Code Online (Sandbox Code Playgroud)

在这里它被排序并转换为数组以传递给碰巧接受数组的其他方法.在其他地方getUsers()可能会这样使用:

List<User> users = group.getUsers();
for(User user : users) {
    if(user.getAge() < 18) {
        throw new IllegalStateException("Underage user in selected group!");
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们只想找到符合某些标准的用户.在这两种情况下ArrayList,实际上不需要复制到中间体 当我们迁移到Java 8时,我们可以用以下getUsers()方法替换方法users():

public Stream<User> users() {
    return users.values().stream();
}
Run Code Online (Sandbox Code Playgroud)

并修改调用者代码.第一个:

someOtherMethod(group.users().sorted().toArray(User[]::new));
Run Code Online (Sandbox Code Playgroud)

第二个:

if(group.users().anyMatch(user -> user.getAge() < 18)) {
    throw new IllegalStateException("Underage user in selected group!");
}
Run Code Online (Sandbox Code Playgroud)

这样它不仅更短,而且可以更快地工作,因为我们跳过了中间复制.

Stream API中的另一个概念点是,根据指南编写的任何流代码都可以通过添加parallel()步骤来并行化.当然,这并不总能提升性能,但它比我预期的更有帮助.通常,如果操作顺序执行0.1ms或更长时间,则可以从并行化中受益.无论如何,我们还没有看到过如此简单的方法在Java中进行并行编程.