image.png

Lambda: 本质是函数式接口的实例(区别:在Python中lambda本质是函数)

image.png
image.png
image.png

函数式接口: 只有一个抽象方法的接口。 可用@functionalInterface来注解。

image.png

代码-内置函数接口Predicate(lambda来作为函数接口的实例)

Predicate<String> pre = x -> x.contains("京")

  1. package com.xj.java;
  2. import org.junit.Test;
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import java.util.function.Predicate;
  6. /**
  7. * @author jia
  8. * @create 2021-12-22 5:31 下午
  9. */
  10. public class LambdaTest {
  11. @Test
  12. public void Test(){
  13. String[] src = {"北京","成都","天津","南京"};
  14. List<String> res = filter(src,x -> x.contains("京"));
  15. System.out.println(res); // [北京, 南京]
  16. }
  17. public static List<String> filter(String[] src, Predicate<String> pre){
  18. // 内置函数接口-Predicate
  19. LinkedList<String> stringFilter = new LinkedList<>();
  20. for (String s : src){
  21. if (pre.test(s))
  22. stringFilter.add(s);
  23. }
  24. return stringFilter;
  25. }
  26. }

方法引用(MethodRef)

image.png
是特殊的lambda表达式。引用已有的实现来替代“函数式接口的实现”,而不用重复实现。 比如下方,Array.sort()中需要传入Comparable接口的实现对象,除了可以传入匿名实现类、和lambda表达式,还可以直接传入已有的接口实现的引用。

  1. String[] stringsArray = {"Hello","World"};
  2. //使用lambda表达式和类型对象的实例方法
  3. Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
  4. //使用方法引用
  5. //引用的是类型对象的实例方法
  6. Arrays.sort(stringsArray, String::compareToIgnoreCase);

引用自定义的接口实现。

  1. class ComparisonProvider{
  2. public int compareByName(Person a,Person b){
  3. return a.getName().compareTo(b.getName());
  4. }
  5. public int compareByAge(Person a,Person b){
  6. return a.getBirthday().compareTo(b.getBirthday());
  7. }
  8. }
  9. ComparisonProvider provider = new ComparisonProvider();
  10. //使用lambda表达式
  11. //对象的实例方法
  12. Arrays.sort(persons,(a,b)->provider.compareByAge(a,b));
  13. //使用方法引用
  14. //引用的是对象的实例方法
  15. Arrays.sort(persons, provider::compareByAge);

甚至可以引用构造方法

  1. public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
  2. DEST transferElements(SOURCE sourceColletions, Supplier<DEST> colltionFactory) {
  3. DEST result = colltionFactory.get();
  4. for (T t : sourceColletions) {
  5. result.add(t);
  6. }
  7. return result;
  8. }
  9. ...
  10. final List<Person> personList = Arrays.asList(persons);
  11. //使用lambda表达式
  12. Set<Person> personSet = transferElements(personList,()-> new HashSet<>());
  13. //使用方法引用
  14. //引用的是构造方法
  15. Set<Person> personSet2 = transferElements(personList, HashSet::new);

Stream API: 函数式编程风格、用于操作容器、

image.png
image.png
image.png
image.png

Stream代码: 分为3部分介绍,对应了Stream的3个过程,Stream实例化,Stream中间操作,Stream终止操作

  1. package com.xj.java;
  2. import org.junit.Test;
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import java.util.List;
  6. import java.util.Set;
  7. import java.util.stream.Collectors;
  8. import java.util.stream.Stream;
  9. /**
  10. * @author jia
  11. * @create 2021-12-23 3:55 下午
  12. */
  13. public class StreamTest {
  14. /**
  15. * Stream分为如下3步。
  16. * */
  17. public static Stream<Integer> step1(){
  18. /**
  19. * 0. Stream分为串行流和并行流。
  20. * */
  21. Stream<Integer> stream = Arrays.asList(1, 2, 3).stream(); // 串行流
  22. Stream<Integer> integerStream = Arrays.asList(1, 2, 3).parallelStream(); // 并行流
  23. /**
  24. * 1. Stream实例化 - 4种方式
  25. * */
  26. // 方式1-集合
  27. Stream<Integer> stream1 = Arrays.asList(1, 2, 3,4,5,6,6,6,6).stream();
  28. // 方式2-数组
  29. Stream<Integer> stream2 = Arrays.stream(new Integer[]{1, 2, 3,4,5,6,6,6,6});
  30. // 方式3-Stream.of静态方法
  31. Stream<Integer> Stream3 = Stream.of(1, 2, 3,4,5,6,6,6,6);
  32. // 方式4-迭代器、生成器
  33. Stream<Integer> stream4 = Stream.iterate(0, t -> t + 1).limit(9);
  34. return stream1;
  35. }
  36. public static Stream<Integer> step2(){
  37. /**
  38. * 2. Stream中间操作
  39. * */
  40. // 1. filter(predict函数式接口实例)
  41. Stream<Integer> filter = step1().filter(x -> x.compareTo(2) > 0);
  42. // 2. limit(int)
  43. Stream<Integer> limit = step1().limit(8);
  44. // 3. skip(int)
  45. Stream<Integer> skip = step1().skip(1);
  46. // 4. distinct() 通过hashCode()和equals()来去重。
  47. Stream<Integer> distinct = step1().distinct();
  48. // 5. map(函数式接口实例) 将流中元素照指定函数映射。
  49. Stream<Integer> map = step1().map(x -> x * 10);
  50. // 6. flatMap(函数式接口实例) 将流中元素照指定函数映射。mapflatmap区别见test_map_flatmap测试。
  51. // 7. 排序
  52. Stream<Integer> sorted = step1().sorted((x, y) -> -1 * Integer.compare(x, y));// 无参数则自然排序
  53. return filter;
  54. }
  55. @Test
  56. public void step3(){
  57. /**
  58. * 3.1 Stream终止操作 -- 查找、遍历
  59. * */
  60. boolean bool;
  61. // 1.allMatch --是否全部匹配条件
  62. bool = step2().allMatch(e -> e > 4);
  63. System.out.println(bool);
  64. // 2. noneMatch-- 是否没有匹配的元素
  65. bool = step2().noneMatch(e -> e == 2);
  66. System.out.println(bool);
  67. // 3.findFirst -- 返回首个元素
  68. System.out.println(step2().findFirst());
  69. // 4. findAny -- 返回任意元素
  70. System.out.println(step2().findAny());
  71. // 5. count -- 总数。类型为long
  72. System.out.println(step2().count());
  73. // 6. 比较
  74. System.out.println(step2().max(Integer::compare)); // 或者(x,y) -> Integer.compare(x,y)和(x,y) -> x-y)等
  75. System.out.println(step2().min(Integer::compare));
  76. // 7.foreach 内部迭代
  77. step2().forEach(e -> System.out.print(e + " "));
  78. System.out.println();
  79. // 8. 对比7 外部迭代-使用集合的迭代
  80. Arrays.asList(1,2,3).forEach(e -> System.out.print(e + " "));
  81. System.out.println();
  82. /**
  83. * 3.2 Stream终止操作 -- 归约 reduce 将流中元素反复以xx方式结合起来,得到一个值。
  84. * */
  85. // 3.2.1 计算数字之和
  86. Integer reduce = Arrays.asList(1,2,3).stream().reduce(0, (a,b) -> a + b);// 或者 Integer::sum
  87. System.out.println(reduce);
  88. // 3.2.2 计算数字之积
  89. Integer reduce1 = Arrays.asList(1, 2, 3).stream().reduce(1, (a, b) -> a * b);
  90. System.out.println(reduce);
  91. /**
  92. * 3.3 Stream终止操作 -- 收集 collect 将流中元素以xx方式收集,比如收集到List,Set,Map
  93. * */
  94. // 3.3.1 - 转为List
  95. List<Integer> collect = Arrays.asList(1, 2, 3).stream().collect(Collectors.toList());
  96. collect.forEach(e -> System.out.print(e + " "));
  97. System.out.println();
  98. // 3.3.2 - 转为Set
  99. Set<Integer> collect1 = Arrays.asList(1, 2, 3).stream().collect(Collectors.toSet());
  100. collect1.forEach(e -> System.out.print(e + " "));
  101. System.out.println();
  102. }
  103. @Test
  104. public void test_map_flatmap(){
  105. /*
  106. 比较mapflatmap的区别。
  107. 采用同一个映射方法,将容器中的字符串拆分为字符。
  108. flatmap: 流{"good","man"} -> 流{'g','o','o','d','m','a','n'}
  109. map: 流{"good","man"} -> 流{流{'g','o','o','d'},流{'m','a','n'}}
  110. */
  111. Stream<String> stream = null;
  112. // flatmap
  113. stream = Arrays.asList("good", "man").stream();
  114. Stream<Character> flatmap_characterStream = stream.flatMap(StreamTest::fromString2Stream);
  115. flatmap_characterStream.forEach(x -> System.out.print(x + " "));
  116. System.out.println();
  117. // map
  118. stream = Arrays.asList("good", "man").stream();
  119. Stream<Stream<Character>> map_streamStream = stream.map(StreamTest::fromString2Stream);
  120. map_streamStream.forEach(x -> x.forEach(s -> System.out.print(s + " "))); // 注意区别
  121. }
  122. public static Stream<Character> fromString2Stream(String str){
  123. ArrayList<Character> characters = new ArrayList<>();
  124. for (char c : str.toCharArray()){
  125. characters.add(c);
  126. }
  127. return characters.stream();
  128. }
  129. }

测试step3()

false true Optional[3] Optional[3] 7 Optional[6] Optional[3] 3 4 5 6 6 6 6 1 2 3 6 6 1 2 3 1 2 3

Optional: 避免空指针问题

使用指南

Optional可以避免显式的空值检查,一般使用方式为T obj = Optional.ofNullable(T t).orElse(T other)T obj = Optional.of(T t).get() 。第一种传入参数t允许为空,以备选对象的方式避免空指针的问题,第二种传入参数t不可为空,以抛异常的方式来避免空指针。 第一种方式类似于python的语法:obj = t or other

image.png

代码-有无Optional的情况下避免空指针的做法

下面是核心代码
image.png

  1. package com.xj.java;
  2. import org.junit.Test;
  3. import java.util.Optional;
  4. /**
  5. * @author jia
  6. * @create 2021-12-23 10:44 下午
  7. */
  8. public class OptionalTest {
  9. @Test
  10. public void PersonTest(){
  11. // 一个人只有左手。没有Optional时,通过提前判断来避免空指针
  12. Person person = new Person();
  13. person.setLeftHand(new Hand("左"));
  14. if (person.getLeftHand() != null){
  15. person.getLeftHand().holdOut();
  16. person.getLeftHand().drawBack();
  17. } else
  18. System.out.println("没有左手");
  19. if (person.getRightHand() != null){
  20. person.getRightHand().holdOut();
  21. person.getRightHand().drawBack();
  22. }else
  23. System.out.println(" !! 没有右手");
  24. }
  25. @Test
  26. public void OptionalPersonTest(){
  27. // 一个人只有左手。有Optional时,无需使用判断就能避免空指针
  28. OptionalPerson person = new OptionalPerson();
  29. person.setLeftHand(new Hand("左"));
  30. person.getLeftHand().holdOut();
  31. person.getLeftHand().drawBack();
  32. person.getRightHand().holdOut();
  33. person.getRightHand().drawBack();
  34. }
  35. }
  36. class OptionalPerson{
  37. // 一般人有两个手,但也有人没有手。
  38. private Hand leftHand = null;
  39. private Hand rightHand = null;
  40. public OptionalPerson() {
  41. }
  42. public Hand getLeftHand() {
  43. Optional<Hand> handOptional = Optional.ofNullable(this.rightHand);
  44. Hand hand = handOptional.orElse(new Hand("!!Optional-(没有右手)"));
  45. return hand;
  46. }
  47. public void setLeftHand(Hand leftHand) {
  48. this.leftHand = leftHand;
  49. }
  50. public Hand getRightHand() {
  51. Optional<Hand> handOptional = Optional.ofNullable(this.rightHand);
  52. Hand hand = handOptional.orElse(new Hand("!!Optional-(没有左手)"));
  53. return hand;
  54. }
  55. public void setRightHand(Hand rightHand) {
  56. this.rightHand = rightHand;
  57. }
  58. }
  59. class Person{
  60. // 一般人有两个手,但也有人没有手。
  61. private Hand leftHand = null;
  62. private Hand rightHand = null;
  63. public Hand getLeftHand() {
  64. return leftHand;
  65. }
  66. public void setLeftHand(Hand leftHand) {
  67. this.leftHand = leftHand;
  68. }
  69. public Hand getRightHand() {
  70. return rightHand;
  71. }
  72. public void setRightHand(Hand rightHand) {
  73. this.rightHand = rightHand;
  74. }
  75. }
  76. class Hand{
  77. // 这是一个手的3个动作。
  78. public String hand = null;
  79. public Hand(String hand) {
  80. this.hand = hand; // 左或右
  81. }
  82. public void drawBack(){
  83. System.out.println(this.hand + "手收回");
  84. }
  85. public void holdOut() {
  86. System.out.println(this.hand + "手伸出");
  87. }
  88. }