Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式
Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
需要注意的是:
Java8 的 Collection 接口有两个获取流的 default 方法,用 default 修饰,因为 List 和 Set 是 Collection 接口的子接口,所以 List,Set 的所有实现类的对象能够直接调用 Collection 中的这两个 default 方法
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
其中 stream()
方法返回一个顺序流,parallelStream()
方法返回一个并行流
举个例子:
@Test
public void test01() {
List<Employee> employees = EmployeeData.getEmployees();
// 调用 Collection 接口中的 stream() 方法
Stream<Employee> stream = employees.stream();
System.out.println(stream);
// 调用 Collection 接口中的 parallelStream() 方法
Stream<Employee> employeeStream = employees.parallelStream();
System.out.println(employeeStream);
}
通过 Java8 中的 Arrays 类中的静态方法 stream()
获取数组流
public static IntStream stream(int[] array) {
return stream(array, 0, array.length);
}
public static LongStream stream(long[] array) {
return stream(array, 0, array.length);
}
举个例子:
@Test
public void test02() {
int[] arr = {1, 2, 3, 4, 5};
// 调用 Arrays 类的 static IntStream stream(int[] array) 方法返回一个 Stream
IntStream stream = Arrays.stream(arr);
Employee employee = new Employee(100, "employee");
Employee employee1 = new Employee(101, "employee2");
Employee[] employees = {employee, employee1};
Stream<Employee> stream1 = Arrays.stream(employees);
}
Stream 类下的 of(T... values)
方法
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
举个例子
@Test
public void test03() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
}
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,这个过程称为惰性求值
共有如下几种方法:
filter(Predicate p)
:接收 Lambda,从流中排除某些元素
distinct()
:通过流所生成元素的 hashCode() 和equals() 去除重复元素
limit(long maxSize)
:截断流,返回给定数量的流
skip(long n)
:跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个, 则返回一个空流。与 limit(n) 互补
@Test
public void test01() {
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
// 查询员工表中工资超过7000的员工的信息
stream.filter(employee -> employee.getSalary() > 7000).forEach(System.out::println);
System.out.println();
// 查询员工表中的前5条记录
employees.stream().limit(5).forEach(System.out::println);
System.out.println();
// 查询员工表中去除前5条记录之后的结果
employees.stream().skip(5).forEach(System.out::println);
System.out.println();
// 去除重复, 需要根据筛选对象重写的hasCode()和equals()方法来去除
employees.stream().distinct().forEach(System.out::println);
}
共有以下几种方法
map(Function f)
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的 StreammapToDouble(ToDoubleFunction f)
:接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStreammapToInt(ToIntFunction f)
:接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStreamflatMap(Function f)
:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流@Test
public void test02() {
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
// 位置1
Stream<String> stringStream = list.stream().map(s -> s.toUpperCase());
stringStream.forEach(System.out::println);
List<Employee> employees = EmployeeData.getEmployees();
// 位置2
Stream<String> nameStream = employees.stream().map(Employee::getName);
nameStream.filter(name -> name.length() > 3).forEach(System.out::println);
System.out.println();
// 位置3
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest01::fromStringToStream);
characterStream.forEach(System.out::print);
}
位置1先获取集合的流,然后将流中的每个元素转换成大写的元素,最终将所有转换完成的元素映射成一个新的流
位置2先获取 Employee 集合的流,然后获取每个 Employee 对象的 name 属性,最终将获取到的所有 name 映射成一个流
位置3先获取集合的流,然后在 flatMap 中传入另外一个流,最后将所有的流连接成为一个流
共有以下几种方法
sorted()
:产生一个新的流,其中按自然顺序排序sorted(Comparator com)
:产生一个新的流,其中按比较器顺序进行排序@Test
public void test04() {
// 自然排序
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.stream().sorted().forEach(integer -> System.out.print(integer + " "));
// 因为Employee没有实现Comparable接口, 此时抛出异常
/*List employees1 = EmployeeData.getEmployees();
employees1.stream().sorted().forEach(System.out::print);*/
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((o1, o2) -> Integer.compare(o1.getAge(), o2.getAge())).forEach(System.out::print);
}
如果获取到的是基本类型的流,则直接使用 sorted()
方法对其中的元素进行排序;如果获取到的是对象类型的流,则对象需要实现 Comparable 接口,并重写里面的 compareTo(T o)
方法
终端操作会从流的流水线生成结果,其结果可以是任何不是流的值,一个流执行了终止操作之后,就不能被再次使用了
共有以下几种方法:
allMatch(Predicate p)
:检查是否匹配所有的元素anyMatch(Predicate p)
:检查是否至少匹配一个元素noneMatch(Predicate p)
:检查是否没有匹配所有元素findFirst()
:返回第一个元素findAny()
:返回当前流中的任意元素count()
:返回流中元素的总数max(Comparator c)
:返回流中的最大值min(Comparator c)
:返回流中的最小值forEach(Consumer c)
:内部迭代器@Test
public void test01() {
// 使用 allMatch 检查是否所有员工的年龄是否大于18
boolean b = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(b);
// 使用 anyMatch 检查是否存在员工的工资大于 1000
boolean b1 = employees.stream().anyMatch(e -> e.getAge() > 1000);
System.out.println(b1);
// 使用 noneMatch 查询是否没有员工姓磊
boolean b2 = employees.stream().noneMatch(e -> e.getName().startsWith("磊"));
System.out.println(b2);
// 使用 findFirst
Optional<Employee> employee = employees.stream().findFirst();
System.out.println(employee);
// 使用 findAny
Optional<Employee> any = employees.stream().findAny();
System.out.println(any);
// 使用 count
long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
System.out.println(count);
// 使用 max
Optional<Employee> max = employees.stream().distinct()
.max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max);
Stream<Integer> salaryStream = employees.stream().map(Employee::getAge);
Optional<Integer> max1 = salaryStream.max(Integer::compare);
System.out.println(max1);
// 使用 min
Optional<Employee> min = employees.stream().min((o1, o2) -> Integer.compare(o1.getAge(), o2.getAge()));
System.out.println(min);
}
共有以下几种方法:
reduce(T identity, BinaryOperator accumulator)
:将流中元素反复结合起来,得到一个值,返回类型 Treduce(BinaryOperator accumulator)
:可以将流中元素反复结合起来,得到一个值。返回 Optional
@Test
public void test02() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 位置1
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);
// 位置2
Optional<Double> reduce1 = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(reduce1);
}
位置1表示对流中的元素,获取第0位以及之后所有元素相加的值;位置2则先获取流中的 Employee 的 salary,然后再对所有的 salary 执行求和操作
共有以下几种方法:
collect(Collector c)
:将流转换为其他形式。接收一个 Collector 接口的实现,将 Stream 中的元素转换成想要的类型其中 Collector 接口中常用下面几种方法:
toList
:返回类型是 List,将流中的元素收集到 List 中toSet
:返回类型是 Set,将流中的元素手机到 Set 中toCollection
:返回类型是 Collection,将流中元素收集到创建的集合中@Test
public void test03() {
List<Employee> collect = employees.stream().filter(employee -> employee.getSalary() > 6000)
.collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println();
Set<Employee> collect1 = employees.stream().filter(employee -> employee.getSalary() > 6000)
.collect(Collectors.toSet());
collect1.forEach(System.out::println);
System.out.println();
Collection<Employee> collect2 = employees.stream().filter(employee -> employee.getSalary() > 6000)
.collect(Collectors.toCollection(ArrayList::new));
collect2.forEach(System.out::println);
}