摘要:本文学习了流式处理,使用新增方法操作集合,以及通过Optional类判断空值。
环境
Windows 10 企业版 LTSC 21H2
Java 1.8
1 简介
1.1 定义
从JDK1.8开始,新增了一系列Stream相关的API用于流式处理,这些API都在java.util.stream
包下,通过Stream可以编写函数式编程风格的代码,使代码更加高效简洁。
1.2 操作方式
流式处理可以分为三个部分:
- 转换成流:将原始数据转换成流对象,以便进行后续操作。
- 中间操作:将原始的Stream经过逻辑处理,生成新的Stream用于继续处理。
- 终止操作:产生结果或者执行其他操作。
2 使用
2.1 转换成流
创建空的Stream对象:
1 | Stream stream = Stream.empty(); |
通过集合类中的stream()
方法或者parallelStream()
方法创建Stream对象:
1 | List<String> list = Arrays.asList("a", "b", "c", "d"); |
通过数组工具类Arrays类的stream()
方法创建Stream对象:
1 | String[] arr = {"a", "b", "c", "d"}; |
通过Stream类中的of()
方法创建Stream对象:
1 | Stream stream = Stream.of("test"); |
通过Stream类中的iterate()
方法创建有序的Stream对象:
1 | public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f); |
通过Stream类中的generate()
方法创建无序的Stream对象:
1 | public static<T> Stream<T> generate(Supplier<T> s); |
2.2 中间操作
多个中间操作可以连接起来形成流水线,在终止操作时进行处理并返回结果,称为惰性求值
,是函数式编程中的一种策略。
2.2.1 过滤
对Stream对象按指定的Predicate进行筛选,将符合条件的元素组成新的Stream对象返回。
语法:
1 | Stream<T> filter(Predicate<? super T> predicate); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).filter(i -> i > 5); |
结果:
1 | 8 |
2.2.2 截取
获取指定的前几个元素组成新的Stream对象返回。
语法:
1 | Stream<T> limit(long maxSize); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).limit(2); |
结果:
1 | 1 |
2.2.3 跳过
跳过指定的前几个元素,将剩下的元素组成新的Stream对象返回。
语法:
1 | Stream<T> skip(long n); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).skip(2); |
结果:
1 | 5 |
2.2.4 去重
调用元素的equals()
方法进行比较,将去重后的元素组成新的Stream对象返回。
语法:
1 | Stream<T> distinct(); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).distinct(); |
结果:
1 | 1 |
2.2.5 排序
调用传入比较器进行比较,将排序后的元素组成新的Stream对象返回。
语法:
1 | Stream<T> sorted(Comparator<? super T> comparator); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).sorted((m, n) -> m - n); |
结果:
1 | 1 |
2.2.6 映射
将Stream中的元素转换成其他元素或者提取信息,调用传入的函数处理每个元素,将处理后的元素组成新的Stream对象返回。
语法:
1 | <R> Stream<R> map(Function<? super T, ? extends R> mapper); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8).map(i -> i + 1); |
结果:
1 | 2 |
2.2.7 扁平映射
将Stream中的元素转换成Stream对象,调用传入的函数处理每个Steam对象,将处理后的Stream对象组成新的Stream对象返回。
语法:
1 | <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); |
示例:
1 | Stream<String> stream = Stream.of("1 8", "5 8").flatMap(s -> Stream.of(s.split(" "))); |
结果:
1 | 1 |
2.3 终止操作
终端操作会使用流水线生成结果,一旦执行终端操作,流就被使用使用了,无法再被使用。
2.3.1 遍历元素
语法:
1 | void forEach(Consumer<? super T> action); |
示例:
1 | Stream<Integer> stream = Stream.of(1, 8, 5, 8); |
结果:
1 | 1 |
2.3.2 检查是否所有元素匹配
如果所有元素都满足条件,那么返回true,否则返回false。
语法:
1 | boolean allMatch(Predicate<? super T> predicate); |
示例:
1 | boolean match = Stream.of("aa11", "bb11").allMatch(e -> e.contains("11")); |
2.3.3 检查是否任意元素匹配
如果任意元素满足条件,就返回true,否则返回false。
语法:
1 | boolean anyMatch(Predicate<? super T> predicate); |
示例:
1 | boolean match = Stream.of("aa11", "bb11").anyMatch(e -> e.contains("aa")); |
2.3.4 检查是否没有元素匹配
如果没有元素满足条件,返回true,否则返回false。
语法:
1 | boolean noneMatch(Predicate<? super T> predicate); |
示例:
1 | boolean match = Stream.of("aa11", "bb11").noneMatch(e -> e.contains("cc")); |
2.3.5 返回首个元素
返回首个元素,使用Optional对象封装。
语法:
1 | Optional<T> findFirst(); |
示例:
1 | Optional<String> find = Stream.of("aa11", "bb11").findFirst(); |
2.3.6 返回任意元素
返回任意元素,通常是处理最快的那个元素,使用Optional对象封装。
语法:
1 | Optional<T> findAny(); |
示例:
1 | Optional<String> find = Stream.of("aa11", "bb11").findAny(); |
2.3.7 返回元素个数
语法:
1 | long count(); |
示例:
1 | long count = Stream.of("aa11", "bb11").count(); |
2.3.8 返回元素最大值
语法:
1 | Optional<T> max(Comparator<? super T> comparator); |
示例:
1 | Optional<Integer> max = Stream.of(1, 8, 5, 8).max((m, n) -> m - n); |
2.3.9 返回元素最小值
语法:
1 | Optional<T> min(Comparator<? super T> comparator); |
示例:
1 | Optional<Integer> min = Stream.of(1, 8, 5, 8).min((m, n) -> m - n); |
2.3.10 收集元素
将流中的元素进行汇总,使用集合收集元素。
可以使用Collectors类提供的静态方法,将流中的元素通过集合收集。
语法:
1 | <R, A> R collect(Collector<? super T, A, R> collector); |
示例:
1 | List<Integer> list = Arrays.asList(1, 8, 5, 8); |
2.3.11 规约元素
将流中的元素反复结合,最终生成单一的结果。
语法:
1 | T reduce(T identity, BinaryOperator<T> accumulator); |
示例:
1 | List<Integer> list = Arrays.asList(1, 8, 5, 8); |
3 Optional类
为了避免产生NullPointException异常,通常的做法是进行if条件判断,但如果代码里面充满了大量的null判断会让程序变的不再优雅。
从JDK1.8开始,可以使用Optional类处理可能为null的变量,在减少NullPointException的同时,也提升了代码的美观度。
3.1 获取
创建空的Optional对象:
1 | Optional<String> name = Optional.empty(); |
包装不为null的对象,如果对象为null,则抛出NullPointException异常:
1 | Optional<String> name = Optional.of(str); |
包装可以为null的对象,如果对象为null,则创建空的Optional对象:
1 | Optional<String> name = Optional.ofNullable(str); |
3.2 常用方法
3.2.1 判断是否为空
使用isPresent()
方法判断Optional对象是否为空,如果为空则返回true,如果不为空则返回false。
示例:
1 | Optional<String> name = Optional.ofNullable(null); |
3.2.2 安全执行方法
使用ifPresent()
方法安全的执行传入的方法,如果不为空则执行方法,如果为空则什么也不做。
示例:
1 | Optional<String> name = Optional.ofNullable("name"); |
3.2.3 获取值
使用get()
方法获取Optional对象的值,如果不为空则返回值,如果为空则抛出NoSuchElementException异常。
示例:
1 | Optional<String> name = Optional.ofNullable("name"); |
3.2.4 获取值或默认值
使用orElse()
方法获取Optional对象的值,如果不为空则返回值,如果为空则返回指定的值。
示例:
1 | Optional<String> name = Optional.ofNullable(null); |
3.2.5 获取值或执行方法
使用orElseGet()
方法获取Optional对象的值,如果不为空则返回值,如果为空则返回执行方法得到的值。
示例:
1 | Optional<String> name = Optional.ofNullable(null); |
3.2.6 获取值或抛出异常
使用orElseThrow()
方法获取Optional对象的值,如果不为空则返回值,如果为空则抛出指定的异常,默认抛出NoSuchElementException异常。
示例:
1 | Optional<String> name = Optional.ofNullable(null); |
3.2.7 过滤
使用filter()
方法过滤Optional对象的值,判断是否满足传入的条件,如果满足则返回原来的Optional对象,如果不满足则创建空的Optional对象返回。
示例:
1 | Optional<String> name = Optional.ofNullable("name").filter(e -> e != null); |
3.2.8 映射
使用map()
方法处理Optional对象的值,如果不为空则使用传入的方法处理并将返回值封装为Optional对象返回,如果为空则创建空的Optional对象返回。
示例:
1 | Optional<Integer> length = Optional.ofNullable("name").map(e -> e.length()); |
3.2.9 扁平映射
使用flatMap()
方法处理Optional对象的值,如果不为空则使用传入的方法处理并将Optional对象返回,如果为空则创建空的Optional对象返回。
示例:
1 | Optional<Integer> length = Optional.ofNullable("name").flatMap(e -> Optional.ofNullable(e.length())); |
3.3 注意事项
比较orElse()方法和orElseGet()方法:
- 当Optional对象不为空时,返回的都是原对象。当Optional对象为空时,orElse()方法返回指定的值,orElseGet()方法返回的是接口调用的返回值。
- 并且当Optional对象不为空时,orElse()方法也会执行,orElseGet()方法不会执行。如果两个方法都返回新对象,orElse()方法会执行初始化,orElseGet()方法不会执行初始化。
比较map()方法和flatMap()方法:
- 如果Optional对象为空,都会创建空对象返回。
- 如果Optional对象不为空,map()方法会将执行方法得到的返回值包装为Optional对象,flatMap()方法会直接返回执行方法得到的Optional对象。
4 集合增强
4.1 工具类
4.1.1 Collector
可以将Collector接口看做是用来处理流的工具,在Collectors类里面封装了很多Collector工具。
4.1.2 Collectors
Collectors类是一个提供了多种Collector接口的工具类。
4.1.2.1 集合
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1.2.2 拼接
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1.2.3 数学
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1.2.4 映射
示例:
1 | List<Score> scoreList = new ArrayList<Score>(); |
4.1.2.5 收集处理
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1.2.6 统计归纳
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.2.1.7 分组
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1.2.8 分区
示例:
1 | List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); |
4.1 遍历集合
4.1.1 遍历List
示例:
1 | List<String> list = new ArrayList<String>(); |
4.1.2 遍历Set
示例:
1 | Set<String> set = new HashSet<String>(); |
4.1.3 遍历Map
示例:
1 | Map<Integer, String> map = new HashMap<Integer, String>(); |
条