文档

Java™ 教程-Java Tutorials 中文版
Trail: Collections
Lesson: Aggregate Operations
主页>集合>聚合操作

问题和练习的答案:聚合操作

问题

  1. 问:一系列聚合操作称为___。
    答:管道

  2. 问:每个管道包含零个或多个___操作。
    答:中间

  3. 问:每个管道以___操作结束。
    答:终端

  4. 问:什么样的操作产生另一个流作为其输出?
    答:中间

  5. 问:描述 forEach 聚合操作与增强的 for 语句或迭代器的不同之处。
    答:forEach 聚合操作允许系统决定迭代发生的“方式”。使用聚合操作可以让你专注于“什么”而不是“如何”。

  6. 问:对或错:流类似于集合,因为它是存储元素的数据结构。
    答:错。与集合不同,流不是数据结构。它改为从源通过管道传递值。

  7. 问:在此代码中标识中间和终端操作:
    double average = roster
        .stream()
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge)
        .average()
        .getAsDouble();
    

    答:中间:filtermapToInt
    终端:average
    终端操作 average 返回 OptionalDouble。然后在该返回的对象上调用 getAsDouble 方法。有关操作是中间操作还是终端操作的信息,参阅 API Specification 始终是一个好主意。

  8. 问:代码 p -> p.getGender() == Person.Sex.MALE 是什么样的例子?
    答:一个 lambda 表达式。

  9. 问:代码 Person::getAge 是什么样的例子?
    答:方法参考。

  10. 问:组合流内容并返回一个值的终端操作被称为什么?
    答:缩减操作。

  11. 问:列出 Stream.reduce 方法和 Stream.collect 方法之间的一个重要区别。
    答:Stream.reduce 在处理元素时始终会创建一个新值。Stream.collect 修改(或改变)现有值。

  12. 问:如果要处理名称流,提取男性名称,并将它们存储在新的 List 中,Stream.reduceStream.collect 哪个是最适合使用的操作?
    答:collect 操作最适合收集到 List

    例:
    List<String> namesOfMaleMembersCollect = roster
        .stream()
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .map(p -> p.getName())
        .collect(Collectors.toList());
    


  13. 问:对或错:聚合操作可以实现与非线程安全集合的并行性。
    答:对,前提是你在操作基础集合时不要修改(mutate)它。

  14. 问:除非另有说明,否则流始终是串行的。你如何请求并行处理流?
    答:通过调用 parallelStream() 而不是 stream() 来获取并行流。

练习

  1. 练习:将以下增强的 for 语句写为具有 lambda 表达式的管道。提示:使用 filter 中间操作和 forEach 终端操作。
    for (Person p : roster) {
        if (p.getGender() == Person.Sex.MALE) {
            System.out.println(p.getName());
        }
    }
    

    答案:
    roster
        .stream()
        .filter(e -> e.getGender() == Person.Sex.MALE)
        .forEach(e -> System.out.println(e.getName());
    
  2. 将以下代码转换为使用 lambda 表达式和聚合操作的新实现,而不是嵌套 for 循环。提示:按顺序调用 filtersortedcollect 操作的管道。
    List<Album> favs = new ArrayList<>();
    for (Album a : albums) {
        boolean hasFavorite = false;
        for (Track t : a.tracks) {
            if (t.rating >= 4) {
                hasFavorite = true;
                break;
            }
        }
        if (hasFavorite)
            favs.add(a);
    }
    Collections.sort(favs, new Comparator<Album>() {
                               public int compare(Album a1, Album a2) {
                                   return a1.name.compareTo(a2.name);
                               }});
    

    答案:
    List<Album> sortedFavs =
      albums.stream()
            .filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4)))
            .sorted(Comparator.comparing(a -> a.name))
            .collect(Collectors.toList());
    

    在这里,我们使用流操作来简化三个主要步骤中的每一个 - 识别相册中的任何曲目是否具有至少为 4 的评级(anyMatch),排序和集合符合我们标准的专辑到 ListComparator.comparing() 方法接受一个提取 Comparable 排序键的函数,并返回一个 Comparator,用于比较该键。


Previous page: Questions and Exercises: Aggregate Operations