⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/weixin_46263782/article/details/121237366 「sid10t.」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前言

早已仰慕 Stream 流久已,终于有机会彻底的了解其特性以及用法了,关于源码的深度理解可能还需要继续增加功底,在学 Stream 的时候,同时认识了强大的 Optional,奈斯!

Stream

流的操作可以分为两种类型:

1)中间操作,可以有多个,每次返回一个新的流,可进行链式操作。

2)终端操作,只能有一个,每次执行完,这个流也就用光光了,无法执行下一个操作,因此只能放在最后。

中间操作不会立即执行,只有等到终端操作的时候,流才开始真正地遍历,用于映射、过滤等。通俗点说,就是一次遍历执行多个操作,性能就大大提高了。

0x1. 创建流

如果是数组的话,可以使用 Arrays.stream() 或者 Stream.of() 创建流;如果是集合的话,可以直接使用 stream() 方法创建流,因为该方法已经添加到 Collection 接口中。

public static void main(String[] args) {
String[] arr = new String[]{"a", "b", "c"};
Stream<String> stream = Arrays.stream(arr);

stream = Stream.of("a", "b", "c");

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
stream = list.stream();
}

查看 Stream 源码的话,你会发现 of() 方法内部其实调用了 Arrays.stream()方法:

public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}

另外,集合还可以调用 parallelStream() 方法创建并发流,默认使用的是 ForkJoinPool.commonPool() 线程池。

List<Long> aList = new ArrayList<>();
Stream<Long> parallelStream = aList.parallelStream();

0x2. 操作流

0x2.1. 过滤

通过 filter() 方法可以从流中筛选出我们想要的元素。

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");
Stream<String> stream = list.stream().filter(element -> element.contains("王"));
stream.forEach(System.out::println);
}

运行结果:

王力宏

0x2.2. 映射

如果想通过某种操作把一个流中的元素转化成新的流中的元素,可以使用 map() 方法。

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");
Stream<Integer> stream = list.stream().map(String::length);
stream.forEach(System.out::println);
}

map() 方法接收的是一个 Function(Java 8 新增的一个函数式接口,接受一个输入参数 T,返回一个结果 R)类型的参数,此时参数 为 String 类的 length 方法,也就是把 Stream<String> 的流转成一个 Stream<Integer> 的流。

运行结果:

3
3
2
3

0x2.3. 匹配

Stream 类提供了三个方法可供进行元素匹配,它们分别是:

  • anyMatch(),只要有一个元素匹配传入的条件,就返回 true。
  • allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回 true。
  • noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部不匹配,则返回 true。

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");

boolean anyMatchFlag = list.stream().anyMatch(element -> element.contains("王"));
boolean allMatchFlag = list.stream().allMatch(element -> element.length() > 1);
boolean noneMatchFlag = list.stream().noneMatch(element -> element.endsWith("沉"));
System.out.println(anyMatchFlag);
System.out.println(allMatchFlag);
System.out.println(noneMatchFlag);
}

运行结果:

true
true
true

0x2.4. 组合

reduce() 方法的主要作用是把 Stream 中的元素组合起来,它有两种用法:

Optional<T> reduce(BinaryOperator<T> accumulator)

没有起始值,只有一个参数,就是运算规则,此时返回 Optional。

T reduce(T identity, BinaryOperator<T> accumulator)

有起始值,有运算规则,两个参数,此时返回的类型和起始值类型一致。

public static void main(String[] args) {
Integer[] ints = {0, 1, 2, 3};
List<Integer> list = Arrays.asList(ints);

Optional<Integer> optional = list.stream().reduce((a, b) -> a + b);
Optional<Integer> optional1 = list.stream().reduce(Integer::sum);
System.out.println(optional.orElse(0));
System.out.println(optional1.orElse(0));

int reduce = list.stream().reduce(6, (a, b) -> a + b);
System.out.println(reduce);
int reduce1 = list.stream().reduce(6, Integer::sum);
System.out.println(reduce1);
}

orElse()方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回;否则返回默认值(上述代码的默认值就是0)。该方法的参数类型和值得类型一致。

运行结果:

6
6
12
12

0x3. 转换流

既然可以把集合或者数组转成流,那么也应该有对应的方法,将流转换回去——collect() 方法就满足了这种需求。

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");

String[] strArray = list.stream().toArray(String[]::new);
System.out.println(Arrays.toString(strArray));

List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());
List<String> list2 = list.stream().collect(Collectors.toCollection(ArrayList::new));
System.out.println(list1);
System.out.println(list2);

String str = list.stream().collect(Collectors.joining(", ")).toString();
System.out.println(str);
}

Collectors 是一个收集器的工具类,内置了一系列收集器实现,比如说 toList() 方法将元素收集到一个新的 java.util.List 中;比如说 toCollection()方法将元素收集到一个新的 java.util.ArrayList 中;比如说 joining() 方法将元素收集到一个可以用分隔符指定的字符串中。

运行结果:

[周杰伦, 王力宏, 陶喆, 林俊杰]
[3, 3, 2, 3]
[周杰伦, 王力宏, 陶喆, 林俊杰]
周杰伦, 王力宏, 陶喆, 林俊杰

0x4. 完整实例

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;

public class Java8Tester {
public static void main(String args[]){
// 计算空字符串
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

System.out.println("列表: " +strings);

count = strings.stream().filter(string->string.isEmpty()).count();
System.out.println("空字符串数量为: " + count);

count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("字符串长度为 3 的数量为: " + count);

filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选后的列表: " + filtered);

mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Squares List: " + squaresList);
System.out.println("列表: " +integers);

IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();

System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
System.out.println("随机数: ");

random.ints().limit(10).sorted().forEach(System.out::println);

// 并行处理
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("空字符串的数量为: " + count);
}
}

运行结果:

列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数:
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2

Optional

Optional 提供了一种用于表示可选值而非空引用的类级别解决方案;

0x1. 创建 Optional 对象

1)可以使用静态方法 empty() 创建一个空的 Optional 对象:

Optional<String> empty = Optional.empty();
System.out.println(empty); // 输出:Optional.empty

2)可以使用静态方法 of() 创建一个非空的 Optional 对象

Optional<String> opt = Optional.of("id10t.");
System.out.println(opt); // 输出:Optional[id10t.]

当然了,传递给 of() 方法的参数必须是非空的,也就是说不能为 null,否则仍然会抛出 NullPointerException

3)可以使用静态方法 ofNullable() 创建一个即可空又可非空的 Optional 对象:

String name = "id10t.";
Optional<String> optOrNull = Optional.ofNullable(name);
System.out.println(optOrNull); // 输出:Optional[id10t.]
optOrNull = Optional.ofNullable(null);
System.out.println(optOrNull); // 输出:Optional.empty

ofNullable() 方法内部有一个三元表达式,如果为参数为 null,则返回私有常量 EMPTY;否则使用 new 关键字创建了一个新的 Optional 对象——不会再抛出 NPE 异常了。

0x2. 判断值是否存在

可以通过方法 isPresent() 判断一个 Optional 对象是否存在,如果存在,该方法返回 true,否则返回 false,取代了 obj != null 的判断。

Optional<String> opt = Optional.of("id10t.");
System.out.println(opt.isPresent()); // 输出:true

Optional<String> optOrNull = Optional.ofNullable(null);
System.out.println(opt.isPresent()); // 输出:false

Java 11 后还可以通过方法 isEmpty() 判断与 isPresent() 相反的结果。

0x3. 非空表达式

Optional 类有一个非常现代化的方法 ifPresent(),允许我们使用函数式编程的方式执行一些代码,因此,我把它称为非空表达式。

Optional<String> opt = Optional.of("id10t.");
opt.ifPresent(str -> System.out.println(str.length()));

Java 9 后还可以通过方法 ifPresentOrElse(action, emptyAction) 执行两种结果,非空时执行 action,空时执行 emptyAction

Optional<String> opt = Optional.ofNullable("id10t.");
// Optional<String> opt = Optional.ofNullable(null);
opt.ifPresentOrElse(
str -> System.out.println(str.length()),
() -> System.out.println("null"));

0x4. 设置(获取)默认值

有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse()orElseGet() 方法就派上用场了。

orElse() 方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回;否则返回默认值。该方法的参数类型和值得类型一致。

String nullName = null;
String name = Optional.ofNullable(nullName).orElse("id10t.");
System.out.println(name); // 输出:id10t.

orElseGet() 方法与 orElse() 方法类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数。

String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()->"id10t.");
System.out.println(name); // 输出:id10t.

从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这样做吗?

Optional 对象的值不为 null 时:

public class A {
public static void main(String[] args) {
String name = "id10t.";
System.out.println("orElse");
String name2 = Optional.ofNullable(name).orElse(getDefaultValue());

System.out.println("orElseGet");
String name3 = Optional.ofNullable(name).orElseGet(A::getDefaultValue);
}

public static String getDefaultValue() {
System.out.println("getDefaultValue");
return "idiot";
}
}

运行结果:

orElse
getDefaultValue
orElseGet

orElseGet() 没有去调用 getDefaultValue(),性能更佳;

0x5. 过滤值

filter()方法的参数类型为 Predicate(Java 8 新增的一个函数式接口),也就是说可以将一个 Lambda 表达式传递给该方法作为条件,如果表达式的结果为 false,则返回一个 EMPTY 的 Optional 对象,否则返回过滤后的 Optional 对象。

public static void main(String[] args) {
String password = "123456";
Optional<String> opt = Optional.ofNullable(password);
System.out.println(opt.filter(pwd -> pwd.length() > 6).isPresent());
}

进阶:

Predicate<String> len6 = pwd -> pwd.length() > 6;
Predicate<String> len10 = pwd -> pwd.length() < 10;

password = "1234567";
opt = Optional.ofNullable(password);
boolean result = opt.filter(len6.and(len10)).isPresent();
System.out.println(result);

0x6. 转换值

map() 方法,该方法可以按照一定的规则将原有 Optional 对象转换为一个新的 Optional 对象,原有的 Optional 对象不会更改。

public staticvoid main(String[] args) {
String name = "id10t.";
Optional<String> nameOptional = Optional.of(name);
Optional<Integer> intOpt = nameOptional
.map(String::length);

System.out.println(intOpt.orElse(0));
}

进阶:

public static void main(String[] args) {
String password = "password";
Optional<String> opt = Optional.ofNullable(password);

Predicate<String> len6 = pwd -> pwd.length() > 6;
Predicate<String> len10 = pwd -> pwd.length() < 10;
Predicate<String> eq = pwd -> pwd.equals("password");

boolean result = opt.map(String::toLowerCase).filter(len6.and(len10 ).and(eq)).isPresent();
System.out.println(result);
}

文章目录
  1. 1. 前言
  2. 2. Stream
    1. 2.1. 0x1. 创建流
    2. 2.2. 0x2. 操作流
      1. 2.2.0.1. 0x2.1. 过滤
      2. 2.2.0.2. 0x2.2. 映射
      3. 2.2.0.3. 0x2.3. 匹配
      4. 2.2.0.4. 0x2.4. 组合
  3. 2.3. 0x3. 转换流
  4. 2.4. 0x4. 完整实例
  • 3. Optional
    1. 3.1. 0x1. 创建 Optional 对象
    2. 3.2. 0x2. 判断值是否存在
    3. 3.3. 0x3. 非空表达式
    4. 3.4. 0x4. 设置(获取)默认值
    5. 3.5. 0x5. 过滤值
    6. 3.6. 0x6. 转换值