Jave8中的stream (二)

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

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

方法类型和管道

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

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

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

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

@Test
public void whenStreamCount_thenGetElementCount() {
    Long empCount = empList.stream()
      .filter(e -> e.getSalary() > 200000)
      .count();
    assertEquals(empCount, new Long(1));
}
复制代码

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

@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 个元素?

@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() 操作开始——它根据我们传递给它的比较器对流元素进行排序。

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

@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 因为结果可能存在也可能不存在(例如,由于过滤):

@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() 来定义比较逻辑:

@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() 方法来判断两个元素是否相等:

@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

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

@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。


相关文章
|
1月前
|
Java
【JavaSE】Stream流
【JavaSE】Stream流
23 0
|
1月前
|
Java
JDK8中Stream的Filter方法
JDK8中Stream的Filter方法
135 0
|
9月前
|
缓存 安全 Java
Java Stream 流详解
Java Stream(流)是Java 8引入的一个强大的新特性,用于处理集合数据。它提供了一种更简洁、更灵活的方式来操作数据,可以大大提高代码的可读性和可维护性。本文将详细介绍Java Stream流的概念、用法和一些常见操作。
216 0
|
9月前
|
Java API
JavaSE之 I/O流(一) stream
JavaSE之 I/O流(一) stream
47 0
|
10月前
|
API
java--Stream流
java--学习笔记
61 0
|
11月前
|
Java API 开发者
【Java】Stream流常用操作以及Optional入门
【Java】Stream流常用操作以及Optional入门
104 0
|
11月前
|
安全 Java
Java Stream流详解
Java Stream流详解
|
SQL 分布式计算 Java
Java Stream流详解(下)
Java Stream流详解(下)
|
Java API
Java Stream流详解(上)
Java Stream流详解(上)
133 0
|
消息中间件 JavaScript Java
Java 8 Stream 之 collect() 的奇技淫巧
Java 8 Stream 之 collect() 的奇技淫巧