前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jave8中的stream (二)

Jave8中的stream (二)

作者头像
用户4235284
发布2022-12-05 14:28:22
3920
发布2022-12-05 14:28:22
举报
文章被收录于专栏:后端学习之道

昨天总结了一下stream中的一些方法的基础使用,现在做一些其他的总结

方法类型和管道

正如我们一直在讨论的,Java 流操作分为中间操作和终端操作。

诸如 filter() 之类的中间操作会返回一个可以在其上进行进一步处理的新流。诸如 forEach() 之类的终端操作将流标记为已使用,之后就不能再进一步使用它。

流管道由流源、零个或多个中间操作和终端操作组成。

这是一个示例流管线,其中Emplist是源,Filter()是中间操作,计数是终端操作:

代码语言:javascript
复制
@Test
public void whenStreamCount_thenGetElementCount() {
    Long empCount = empList.stream()
      .filter(e -> e.getSalary() > 200000)
      .count();

    assertEquals(empCount, new Long(1));
}

一些操作被认为是短路操作。短路操作允许对无限流的计算在有限时间内完成:

代码语言:javascript
复制
@Test
public void whenLimitInfiniteStream_thenGetFiniteElements() {
    Stream<Integer> infiniteStream = Stream.iterate(2, i -> i * 2);

    List<Integer> collect = infiniteStream
      .skip(3)
      .limit(5)
      .collect(Collectors.toList());

    assertEquals(collect, Arrays.asList(16, 32, 64, 128, 256));
}

在这里,我们使用短路操作Skip()跳过前3个元素,并限制()限制使用使用Iterate()生成的无限流中的5个元素。

稍后,我们将更多地谈论无限流。

“懒”加载

Java 流最重要的特性之一是它们允许通过惰性求值进行显着优化。

仅在启动终端操作时才对源数据进行计算,并且仅在需要时消耗源元素。

所有中间操作都是惰性的,因此在实际需要处理结果之前不会执行它们。

例如,考虑我们之前看到的 findFirst() 示例。 map() 操作在这里执行了多少次? 4 次,因为输入数组包含 4 个元素?

代码语言:javascript
复制
@Test
public void whenFindFirst_thenGetFirstEmployeeInStream() {
    Integer[] empIds = { 1, 2, 3, 4 };
    
    Employee employee = Stream.of(empIds)
      .map(employeeRepository::findById)
      .filter(e -> e != null)
      .filter(e -> e.getSalary() > 100000)
      .findFirst()
      .orElse(null);
    
    assertEquals(employee.getSalary(), new Double(200000));
}

Stream 执行映射和两个过滤操作,一次一个元素。

它首先对 id 1 执行所有操作。由于 id 1 的薪水不大于 100000,因此处理转到下一个元素。

Id 2 满足两个过滤器谓词,因此流计算终端操作 findFirst() 并返回结果。

没有对 id 3 和 4 执行任何操作。

延迟处理流可以避免在不必要时检查所有数据。当输入流是无限的而不仅仅是非常大时,这种行为变得更加重要。

Stream的比较操作
sorted

让我们从 sorted() 操作开始——它根据我们传递给它的比较器对流元素进行排序。

例如,我们可以根据员工的姓名对员工进行排序:

代码语言:javascript
复制
@Test
public void whenSortStream_thenGetSortedStream() {
    List<Employee> employees = empList.stream()
      .sorted((e1, e2) -> e1.getName().compareTo(e2.getName()))
      .collect(Collectors.toList());

    assertEquals(employees.get(0).getName(), "Bill Gates");
    assertEquals(employees.get(1).getName(), "Jeff Bezos");
    assertEquals(employees.get(2).getName(), "Mark Zuckerberg");
}

请注意,短路不会用于排序()。

这意味着在上面的示例中,即使我们在sorted()之后使用了findfirst(),所有元素的排序也是在应用findfirst()之前完成的。发生这种情况是因为操作不知道第一个元素在整个流进行排序之前。

min and max

顾名思义,min() 和 max() 基于比较器分别返回流中的最小和最大元素。它们返回 Optional 因为结果可能存在也可能不存在(例如,由于过滤):

代码语言:javascript
复制
@Test
public void whenFindMin_thenGetMinElementFromStream() {
    Employee firstEmp = empList.stream()
      .min((e1, e2) -> e1.getId() - e2.getId())
      .orElseThrow(NoSuchElementException::new);

    assertEquals(firstEmp.getId(), new Integer(1));
}

我们也可以避免使用 Comparator.comparing() 来定义比较逻辑:

代码语言:javascript
复制
@Test
public void whenFindMax_thenGetMaxElementFromStream() {
    Employee maxSalEmp = empList.stream()
      .max(Comparator.comparing(Employee::getSalary))
      .orElseThrow(NoSuchElementException::new);

    assertEquals(maxSalEmp.getSalary(), new Double(300000.0));
}
distinct

distinct() 不接受任何参数并返回流中的不同元素,消除重复。它使用元素的 equals() 方法来判断两个元素是否相等:

代码语言:javascript
复制
@Test
public void whenApplyDistinct_thenRemoveDuplicatesFromStream() {
    List<Integer> intList = Arrays.asList(2, 5, 3, 2, 4, 3);
    List<Integer> distinctIntList = intList.stream().distinct().collect(Collectors.toList());
    
    assertEquals(distinctIntList, Arrays.asList(2, 5, 3, 4));
}
allMatch, anyMatch,  and noneMatch

这些操作都采用谓词并返回布尔值。应用短路并在确定答案后立即停止处理:

代码语言:javascript
复制
@Test
public void whenApplyMatch_thenReturnBoolean() {
    List<Integer> intList = Arrays.asList(2, 4, 5, 6, 8);
    
    boolean allEven = intList.stream().allMatch(i -> i % 2 == 0);
    boolean oneEven = intList.stream().anyMatch(i -> i % 2 == 0);
    boolean noneMultipleOfThree = intList.stream().noneMatch(i -> i % 3 == 0);
    
    assertEquals(allEven, false);
    assertEquals(oneEven, true);
    assertEquals(noneMultipleOfThree, false);
}

AllMatch()检查流中所有元素是否为true。在这里,它一旦遇到5,它就会返回False,这是不可分解的2。

AnyMatch()检查流中任何一个元素是否为true true。在这里,再次应用短路,并在第一个元素之后立即返回TRUE。

nonematch()检查是否没有匹配谓词的元素。在这里,它只会在遇到6的6时立即返回错误,这是可以除以3的3。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • “懒”加载
    • sorted
      • min and max
        • distinct
          • allMatch, anyMatch,  and noneMatch
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档