Java Stream流全方位指南与多元实例
Java Stream流最详尽教程
前言
我在日常项目中频繁使用Stream流,但对其理解尚浅,因此在此深入探究。使用Stream流时通常会涉及Java8的几项新特性,接下来我会简要介绍这些知识,以便在学习或应用Stream流时更为顺畅。
1. Lambda表达式
建议先熟悉函数式接口
1.1 语法规则
parameter -> expression body;
1.2 无参数的情况
当没有参数时,可呈现单条语句或多条语句的形式。例如:
()->System.out.println("baicaizhi");
()->{
System.out.println("baicaizhi1");
System.out.println("baicaizhi1");
}
1.3 单参数的情况
对于单个参数,有单条语句或多条语句的表现。比如:
a->System.out.println(a);
a->{
System.out.println(a);
System.out.println(a);
}
1.4 多参数的情况
多个参数时,有单条语句或多条语句的形式。例如:
(a,b)->a+b;
(a,b)->{
int c = a+b;
System.out.println(c);
}
2. 方法引用
应用场景:可用于静态方法调用或实例创建等情况
Test::new
Test::getName
3. Optional类
以下是Optional接口的相关信息:
接口方法 | 功能描述 |
---|---|
Optional empty() | 创建一个空的Optional实例 |
Optional of(T value) | 创建一个非空的Optional实例,如果传入值为null则报错 |
Optional ofNullable(T value) | 创建一个Optional实例,允许值为null |
T get() | 获取实例中的泛型值,若值为空则抛出异常 |
boolean isPresent() | 检查实例是否非空,非空则返回true |
boolean isEmpty() | 检查实例是否为空,为空则返回true |
ifPresent(Consumer) | 当实例非空时执行指定的消费操作 |
ifPresentOrElse(Consumer, Runnable) | 两个参数,分别在实例非空和为空时执行相应操作 |
Optional filter | 对实例进行过滤操作 |
Optional map(Function) | 进行转换操作 |
Optional flatMap(Function) | 多层转换操作 |
Optional or(Supplier) | 当实例为空时根据提供的供应函数创建新的Optional实例 |
T orElse(T) | 当实例为空时获取指定的默认值 |
T orElseThrow() | 非空时返回实例值,为空则抛出NoSuchElementException |
T orElseThrow(Supplier) | 非空时返回实例值,为空则抛出指定异常 |
4. Stream流概述
4.1.1 Stream流的定义
Stream流可将待处理的元素集合视为一种流动的数据,在流的处理过程中,借助Stream API对流中的元素开展各类操作,例如筛选、排序、聚合等。
4.1.2 Stream流的创建方式及操作分类
Stream流能够由数组或集合来创建,对流的操作可分为两类:
4.1.2.1 中间操作
中间操作会每次返回一个新的流,并且可以有多个中间操作。
4.1.2.2 终端操作
终端操作每一个流仅能执行一次,终端操作完成后流便无法再被使用,终端操作通常会生成一个新的集合或值。
4.1.3 Stream流的特性
- Stream流并不存储数据,而是依据特定规则对数据进行运算,通常会输出结果。
- Stream流不会对数据源进行修改,一般会生成一个新的集合或值。
- Stream流具备延迟执行特性,仅有在调用终端操作时,中间操作才会得以执行。
4.2 Stream流的创建
4.2.1 通过java.util.Collection.stream()方法利用集合创建流
List<String> list = Arrays.asList("a", "b", "c"); // 创建顺序流
Stream<String> stream = list.stream(); // 创建并发流
Stream<String> stringStream = list.parallelStream();
4.2.2 使用java.util.Arrays.stream(T[] array)方法利用数组创建流
//数组创建流
int[] array = {1,2,3};
IntStream stream1 = Arrays.stream(array);
4.2.3 使用Stream的静态方法:of()、iterate()、generate()
//stream静态方法创建流
Stream<Integer> integerStream = Stream.of(1, 2);
Stream<Integer> iterate = Stream.iterate(0, x -> x = 3);
Stream<Double> limit = Stream.generate(Math::random).limit(3);
4.2.4 顺序流转换成并发流
//顺序流转换成并发流
Optional<String> first = list.stream().parallel().filter(x -> x > 6).findFirst();
4.3 Stream流的使用
4.3.1 数据准备
class Person {
private String name; // 姓名
private int salary; // 薪资
private int age; // 年龄
private String sex; //性别
private String area; // 地区
// 构造方法
public Person(String name, int salary, int age,String sex,String area) {
this.name = name;
this.salary = salary;
this.age = age;
this.sex = sex;
this.area = area;
}
// 省略了get和set,请自行添加
}
4.3.2 Stream流的使用
4.3.2.1 遍历与匹配(foreach/find/match)
Stream流同样支持像集合那样的遍历和元素匹配操作,不过Stream流中的元素是以Optional类型呈现的。Stream流的遍历和匹配操作较为简便。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 7, 6, 5, 8);
// 遍历输出符合条件的元素
list.stream().filter(x -> x > 6).forEach(System.out::println);
// 匹配第一个元素
Optional<Integer> first = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意元素(适用于并行流)
Optional<Integer> any = list.parallelStream().filter(x -> x > 6).findAny();
// 检查是否存在符合特定条件的元素
boolean b = list.stream().anyMatch(x -> x < 6);
System.out.println("匹配到的第一个值:" + first.get());
System.out.println("匹配到的任意值:" + any.get());
System.out.println("是否存在小于6的值:" + b);
4.3.2.2 筛选操作
筛选操作是按照一定规则对Stream流中的元素进行校验,将符合条件的元素提取到新流中的操作。
4.3.2.3 聚合操作(max/min/count)
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 11,"male", "New York"));
personList.add(new Person("Jack", 7000, 12,"male", "Washington"));
personList.add(new Person("Lily", 7800, 13,"female", "Washington"));
personList.add(new Person("Anni", 8200, 14,"female", "New York"));
personList.add(new Person("Owen", 9500, 15,"male", "New York"));
personList.add(new Person("Alisa", 7900, 16,"female", "New York"));
List<Integer> list = Arrays.asList(1,2,3,4,7,6,5,8);
//筛选出Integer集合中大于7的元素,并打印出来
list.stream().filter(x->x>7).forEach(System.out::println);
//筛选员工中工资高于8000的人,并形成新的集合。 形成新集合依赖collect(收集)
List<String> collect = personList.stream().filter(value -> value.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
System.out.println("工资高于8000"+collect);
4.3.2.4 映射操作(map/flatMap)
映射操作可将一个Stream流的元素按照特定映射规则映射到另一个流中,分为map和flatMap:
- map:接收一个函数作为参数,该函数会应用到每个元素上,并将其映射为新元素。
- flatMap:接收一个函数作为参数,将流中的每个值转换成另一个流,然后将所有流连接成一个流。
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 11,"male", "New York"));
personList.add(new Person("Jack", 7000, 12,"male", "Washington"));
personList.add(new Person("Lily", 7800, 13,"female", "Washington"));
personList.add(new Person("Anni", 8200, 14,"female", "New York"));
personList.add(new Person("Owen", 9500, 15,"male", "New York"));
personList.add(new Person("Alisa", 7900, 16,"female", "New York"));
List<Integer> list = Arrays.asList(1,2,3,4,7,6,5,8);
List<String> strList = Arrays.asList("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
//英文字符串数组的元素全部改为大写。整数数组每个元素+3
List<Integer> collect = list.stream().map(x -> x + 3).collect(Collectors.toList());
List<String> collect1 = strList.stream().map(String::toUpperCase).collect(Collectors.toList());
//将员工的薪资全部增加1000
//不改变源集合的方式
List<Person> collect2 = personList.stream().map(person -> {
Person person1 = new Person(person.getName(), 0, person.getAge(), person.getSex(), person.getArea());
person1.setSalary(person.getSalary() + 1000);
return person1;
}).collect(Collectors.toList());
//改变源集合的方式
List<Person> collect3 = personList.stream().map(person -> {
person.setSalary(person.getSalary() + 1000);
return person;
}).collect(Collectors.toList());
//将两个字符数组合并成一个新的字符数组
List<String> collect4 = strList.stream().flatMap(s -> {
String[] s2 = s.split(",");
return Arrays.stream(s2);
}).collect(Collectors.toList());
System.out.println("每个元素大写:" + collect1);
System.out.println("每个元素+3:" + collect);
//注意,执行的时候分开执行,否则看不出来效果
System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
System.out.println("一次改动后:" + collect2.get(0).getName() + "-->" + collect2.get(0).getSalary());
System.out.println("二次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
System.out.println("二次改动后:" + collect3.get(0).getName() + "-->" + collect3.get(0).getSalary());
System.out.println("处理前的集合:" + strList);
System.out.println("处理后的集合:" + collect4);
4.3.2.5 归约操作(reduce)
归约操作是将一个Stream流缩减为一个值,可实现对集合的求和、求乘积和求最值等操作。
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 11,"male", "New York"));
personList.add(new Person("Jack", 7000, 12,"male", "Washington"));
personList.add(new Person("Lily", 7800, 13,"female", "Washington"));
personList.add(new Person("Anni", 8200, 14,"female", "New York"));
personList.add(new Person("Owen", 9500, 15,"male", "New York"));
personList.add(new Person("Alisa", 7900, 16,"female", "New York"));
List<Integer> list = Arrays.asList(1,2,3,4,7,6,5,8);
List<String> strList = Arrays.asList("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
// 求Integer集合的元素之和、乘积和最大值
// 求和方式1
Optional<Integer> reduce = list.stream().reduce((x, y) -> x + y);
// 求和方式2
Optional<Integer> reduce1 = list.stream().reduce(Integer::sum);
// 求和方式3
Integer reduce2 = list.stream().reduce(0, Integer::sum);
// 求乘积
Optional<Integer> reduce3 = list.stream().reduce((x, y) -> x * y);
// 求最大值方式1
Optional<Integer> reduce4 = list.stream().reduce((x, y) -> x > y ? x : y);
// 求最大值写法2
Integer reduce5 = list.stream().reduce(1, Integer::max);
// 求所有员工的工资之和和最高工资
// 求和方式1
Optional<Integer> reduce7 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
// 求和方式2
Integer reduce6 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(),(sum1,sum2)->sum1+sum2);
// 求和方式3
Integer reduce8 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
// 求最高工资方式1:
Integer reduce9 = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),Integer::max);
// 求最高工资方式2:
Integer reduce10 = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), (max1, max2) -> max1 > max2 ? max1 : max2);
System.out.println("list求和:" + reduce.get() + "," + reduce1.get() + "," + reduce2);
System.out.println("list求积:" + reduce3.get());
System.out.println("list求最大值:" + reduce4.get() + "," + reduce5);
System.out.println("工资之和:" + reduce7.get() + "," + reduce6 + "," + reduce8);
System.out.println("最高工资:" + reduce9 + "," + reduce10);
4.3.2.6 收集操作(collect)
collect操作可将Stream流中的数据收集起来,最终可收集成一个值或新集合,主要依赖java.util.stream.Collectors类内置的静态方法。
4.3.2.6.1 归集(toList/toSet/toMap)
由于Stream流不存储数据,处理完流中数据后需将其归集到新集合,toList、toSet和toMap较为常用,还有toCollection、toConcurrentMap等复杂用法。
```
List
personList.add(new Person("Tom", 8900, 11,"male", "New York"));
personList.add(new Person("Jack", 7000, 12,"male", "Washington"));
personList.add(new Person("Lily", 7800, 13,"female", "Washington"));
personList.add(new Person("Anni", 8200, 14,"female", "New York"));
personList.add(new Person("Owen", 9500, 15,"male", "New York"));
personList.add(new Person("Alisa", 7900, 16,"female", "New York"));
List
List
List
Set
Map
文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/12640.html