- 前言
- Stream
- 0x1. 创建流
- 0x2. *** 作流
- 0x2.1. 过滤
- 0x2.2. 映射
- 0x2.3. 匹配
- 0x2.4. 组合
- 0x3. 转换流
- 0x4. 完整实例
- Optional
- 0x1. 创建 Optional 对象
- 0x2. 判断值是否存在
- 0x3. 非空表达式
- 0x4. 设置(获取)默认值
- 0x5. 过滤值
- 0x6. 转换值
- 后记
早已仰慕 Stream 流久已,终于有机会彻底的了解其特性以及用法了,关于源码的深度理解可能还需要继续增加功底,在学 Stream 的时候,同时认识了强大的 Optional,奈斯!
接下来的博文直接上用法了,想了解更多,建议阅读以下两篇博文:
一文带你入门Java Stream流,太强了
Java 8 Optional 最佳指南
Stream
流的 *** 作可以分为两种类型:
1)中间 *** 作,可以有多个,每次返回一个新的流,可进行链式 *** 作。
2)终端 *** 作,只能有一个,每次执行完,这个流也就用光光了,无法执行下一个 *** 作,因此只能放在最后。
中间 *** 作不会立即执行,只有等到终端 *** 作的时候,流才开始真正地遍历,用于映射、过滤等。通俗点说,就是一次遍历执行多个 *** 作,性能就大大提高了。
如果是数组的话,可以使用 Arrays.stream() 或者 Stream.of() 创建流;如果是集合的话,可以直接使用 stream() 方法创建流,因为该方法已经添加到 Collection 接口中。
public static void main(String[] args) { String[] arr = new String[]{"a", "b", "c"}; Streamstream = Arrays.stream(arr); stream = Stream.of("a", "b", "c"); List list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); stream = list.stream(); }
查看 Stream 源码的话,你会发现 of() 方法内部其实调用了 Arrays.stream()方法:
public staticStream of(T... values) { return Arrays.stream(values); }
另外,集合还可以调用 parallelStream() 方法创建并发流,默认使用的是 ForkJoinPool.commonPool() 线程池。
ListaList = new ArrayList<>(); Stream parallelStream = aList.parallelStream();
0x2. *** 作流 0x2.1. 过滤
通过 filter() 方法可以从流中筛选出我们想要的元素。
public static void main(String[] args) { Listlist = new ArrayList<>(); list.add("周杰伦"); list.add("王力宏"); list.add("陶喆"); list.add("林俊杰"); Stream stream = list.stream().filter(element -> element.contains("王")); stream.forEach(System.out::println); }
运行结果:
王力宏
0x2.2. 映射
如果想通过某种 *** 作把一个流中的元素转化成新的流中的元素,可以使用 map() 方法。
public static void main(String[] args) { Listlist = new ArrayList<>(); list.add("周杰伦"); list.add("王力宏"); list.add("陶喆"); list.add("林俊杰"); Stream stream = list.stream().map(String::length); stream.forEach(System.out::println); }
map() 方法接收的是一个 Function(Java 8 新增的一个函数式接口,接受一个输入参数 T,返回一个结果 R)类型的参数,此时参数 为 String 类的 length 方法,也就是把 Stream
运行结果:
3 3 2 3
0x2.3. 匹配
Stream 类提供了三个方法可供进行元素匹配,它们分别是:
-
anyMatch(),只要有一个元素匹配传入的条件,就返回 true。
-
allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回 true。
-
noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部不匹配,则返回 true。
public static void main(String[] args) { Listlist = 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
没有起始值,只有一个参数,就是运算规则,此时返回 Optional。
T reduce(T identity, BinaryOperator
有起始值,有运算规则,两个参数,此时返回的类型和起始值类型一致。
public static void main(String[] args) { Integer[] ints = {0, 1, 2, 3}; Listlist = Arrays.asList(ints); Optional optional = list.stream().reduce((a, b) -> a + b); Optional 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) { Listlist = new ArrayList<>(); list.add("周杰伦"); list.add("王力宏"); list.add("陶喆"); list.add("林俊杰"); String[] strArray = list.stream().toArray(String[]::new); System.out.println(Arrays.toString(strArray)); List list1 = list.stream().map(String::length).collect(Collectors.toList()); List 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[]){ // 计算空字符串 Liststrings = 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 提供了一种用于表示可选值而非空引用的类级别解决方案;
1)可以使用静态方法 empty() 创建一个空的 Optional 对象:
Optionalempty = Optional.empty(); System.out.println(empty); // 输出:Optional.empty
2)可以使用静态方法 of() 创建一个非空的 Optional 对象
Optionalopt = Optional.of("id10t."); System.out.println(opt); // 输出:Optional[id10t.]
当然了,传递给 of() 方法的参数必须是非空的,也就是说不能为 null,否则仍然会抛出 NullPointerException。
3)可以使用静态方法 ofNullable() 创建一个即可空又可非空的 Optional 对象:
String name = "id10t."; OptionaloptOrNull = 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 异常了。
可以通过方法 isPresent() 判断一个 Optional 对象是否存在,如果存在,该方法返回 true,否则返回 false,取代了 obj != null 的判断。
Optionalopt = Optional.of("id10t."); System.out.println(opt.isPresent()); // 输出:true Optional optOrNull = Optional.ofNullable(null); System.out.println(opt.isPresent()); // 输出:false
Java 11 后还可以通过方法 isEmpty() 判断与 isPresent() 相反的结果。
0x3. 非空表达式
Optional 类有一个非常现代化的方法 ifPresent(),允许我们使用函数式编程的方式执行一些代码,因此,我把它称为非空表达式。
Optionalopt = Optional.of("id10t."); opt.ifPresent(str -> System.out.println(str.length()));
Java 9 后还可以通过方法 ifPresentOrElse(action, emptyAction) 执行两种结果,非空时执行 action,空时执行 emptyAction。
Optionalopt = Optional.ofNullable("id10t."); // Optional 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(),性能更佳;
filter() 方法的参数类型为 Predicate(Java 8 新增的一个函数式接口),也就是说可以将一个 Lambda 表达式传递给该方法作为条件,如果表达式的结果为 false,则返回一个 EMPTY 的 Optional 对象,否则返回过滤后的 Optional 对象。
public static void main(String[] args) { String password = "123456"; Optionalopt = Optional.ofNullable(password); System.out.println(opt.filter(pwd -> pwd.length() > 6).isPresent()); }
进阶:
Predicatelen6 = pwd -> pwd.length() > 6; Predicate 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."; OptionalnameOptional = Optional.of(name); Optional intOpt = nameOptional .map(String::length); System.out.println(intOpt.orElse(0)); }
进阶:
public static void main(String[] args) { String password = "password"; Optionalopt = Optional.ofNullable(password); Predicate len6 = pwd -> pwd.length() > 6; Predicate len10 = pwd -> pwd.length() < 10; Predicate eq = pwd -> pwd.equals("password"); boolean result = opt.map(String::toLowerCase).filter(len6.and(len10 ).and(eq)).isPresent(); System.out.println(result); }
后记
感谢大佬沉默王二的文章,参考链接如下:
一文带你入门Java Stream流,太强了
Java 8 Optional 最佳指南
现在就处于查漏补缺的状态,缺啥补啥,夯实基础!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)