文档

Java™ 教程
路径: 集合
课程: 聚合操作
首页 > 集合 > 聚合操作

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

问题

  1. Q: 一系列聚合操作被称为___ 。
    A: 管道(Pipeline)

  2. Q: 每个管道包含零个或多个___ 操作。
    A: 中间(Intermediate)

  3. Q: 每个管道以一个___ 操作结束。
    A: 终端(Terminal)

  4. Q: 什么样的操作会产生另一个流作为输出?
    A: 中间(Intermediate)

  5. Q: 描述一种forEach聚合操作与增强的for语句或迭代器的不同之处。
    A: forEach聚合操作让系统决定“如何”进行迭代。使用聚合操作让您专注于“做什么”而不是“如何”。

  6. Q: 真或假:流与集合相似,因为它是存储元素的数据结构。
    A: 假。与集合不同,流不是数据结构。它通过管道从源头传递值。

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

    A: 中间操作:filtermapToInt
    终端操作:average
    终端操作average返回一个OptionalDouble。然后在返回的对象上调用getAsDouble方法。查阅API规范了解操作是中间操作还是终端操作的信息是一个很好的习惯。

  8. Q: 代码 p -> p.getGender() == Person.Sex.MALE 是什么的示例?
    A: Lambda表达式。

  9. Q: 代码 Person::getAge 是什么的示例?
    A: 方法引用。

  10. Q: 合并流内容并返回一个值的终端操作被称为什么?
    A: 归约(Reduction)操作。

  11. Q: Stream.reduce方法和Stream.collect方法之间的一个重要区别是什么?
    A: Stream.reduce在处理元素时总是创建一个新值。Stream.collect修改(或改变)现有值。

  12. Q: 如果您想处理一个名称流,提取男性名称并将它们存储在新的List中,是使用Stream.reduce还是Stream.collect最合适?
    A: 收集(collect)操作最适合收集到List中。

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


  13. Q: 真或假:聚合操作使得能够使用非线程安全集合实现并行处理。
    A: 真,前提是在操作集合时不修改(改变)基础集合。

  14. Q: 流始终是串行的,除非另有指定。如何请求以并行方式处理流?
    A: 通过调用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)、排序和将符合我们条件的专辑收集到一个List中。 Comparator.comparing()方法接受一个提取Comparable排序键的函数,并返回一个以该键进行比较的Comparator


上一页:问题和练习:聚合操作