• Java基础深化和提高 ---- 函数式编程 Lambda


    Lambda表达式介绍

    Lambda简介

     Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内 部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作 中,可以极大地优化代码结构。

     在Java语言中,可以为变量赋予一个值:

     能否把一个代码块赋给一变量吗?

     在Java 8之前,这个是做不到的。但是Java 8问世之后,利用 Lambda特性,就可以做到了。

     甚至我们可以让语法变得更简洁

     在Java 8里面,所有的Lambda的类型都是一个接口,而Lambda表 达式本身,也就是”那段代码“,需要是这个接口的实现。这是我认 为理解Lambda的一个关键所在,简而言之就是,Lambda表达式本 身就是一个接口的实现。直接这样说可能还是有点让人困扰,我们 继续看看例子。我们给上面的aBlockOfCode加上一个类型:

     这种只有一个接口函数需要被实现的接口类型,我们叫它”函数式接 口“。为了避免后来的人在这个接口中增加接口函数导致其有多个接 口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上 一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接 口函数了。

     Lambda作用

    最直观的作用就是使得代码变得异常简洁。

     接口要求

     虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不 是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接 口中只能有一个需要被实现的方法,不是规定接口中只能有一个方 法。 jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默 认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使 用。

    @FunctionalInterface注解作用

    @FunctionalInterface标记在接口上,“函数式接口”是指仅仅只包含 一个抽象方法的接口。

     Lambda表达式语法

     语法结构

    1. (parameters) -> expression
    2. (parameters) ->{ statements;}

    语法形式为 () -> {}: () 用来描述参数列表,如果有多个参数,参数之间用逗号隔开,如 果没有参数,留空即可; -> 读作(goes to),为 lambda运算符 ,固定写法,代表指向动作; {} 代码块,具体要做的事情,也就是方法体内容;

    Lambda表达式的重要特征

    可选类型声明:不需要声明参数类型,编译器可以统一识别参数 值。 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定 义圆括号。 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自 动返回值,大括号需要指定明表达式返回了一个数值。 

     Lambda案例

    1. // 1. 不需要参数,返回值为 5
    2. () -> 5
    3. // 2. 接收一个参数(数字类型),返回其2倍的值
    4. x -> 2 * x
    5. // 3. 接受2个参数(数字),并返回他们的差值
    6. (x, y) -> x – y
    7. // 4. 接收2个int型整数,返回他们的和
    8. (int x, int y) -> x + y
    9. // 5. 接受一个 string 对象,并在控制台打印,不返回任何
    10. 值(看起来像是返回void)
    11. (String s) -> System.out.print(s)

    Lambda表达式入门案例

    定义函数接口

    1. /**
    2. * 无返回值,无参数
    3. */
    4. @FunctionalInterface
    5. interface NoReturnNoParam{
    6. void method();
    7. }
    8. /**
    9. * 无返回值,有一个参数
    10. */
    11. @FunctionalInterface
    12. interface NoReturnOneParam{
    13. void method(int a);
    14. }
    15. /**
    16. * 无返回值,有多个参数
    17. */
    18. @FunctionalInterface
    19. interface NoReturnMultiParam{
    20. void method(int a,int b);
    21. }
    22. /**
    23. * 有返回值,无参数
    24. */
    25. @FunctionalInterface
    26. interface ReturnNoParam{
    27. int method();
    28. }
    29. /**
    30. * 有返回值,有一个参数
    31. */
    32. @FunctionalInterface
    33. interface ReturnOneParam{
    34. int method(int a);
    35. }
    36. /**
    37. * 有返回值,有多个参数
    38. */
    39. @FunctionalInterface
    40. interface ReturnMultiParam{
    41. int method(int a,int b);
    42. }

    实现函数接口

    1. public static void main(String[] args) {
    2. /**
    3. * 无返回值,无参数
    4. */
    5. NoReturnNoParam noReturnNoParam = ()->{
    6. System.out.println("NoReturnNoParam");
    7. };
    8. noReturnNoParam.method();
    9. /**
    10. * 无返回值,有一个参数
    11. */
    12. NoReturnOneParam noReturnOneParam = (int a)->{
    13. System.out.println("NoReturnOneParam"+a);
    14. };
    15. noReturnOneParam.method(10);
    16. /**
    17. * 无返回值,有多个参数
    18. */
    19. NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
    20. System.out.println("NoReturnMultiParam "+a+"\t"+b);
    21. };
    22. noReturnMultiParam.method(10,20);
    23. /**
    24. * 有返回值,无参数
    25. */
    26. ReturnNoParam returnNoParam = ()->{
    27. System.out.print("ReturnNoParam ");
    28. return 10;
    29. };
    30. System.out.println(returnNoParam.method());
    31. /**
    32. * 有返回值,有一个参数
    33. */
    34. ReturnOneParam returnOneParam = (int a)->{
    35. System.out.print("ReturnOneParam ");
    36. return a;
    37. };
    38. System.out.println(returnOneParam.method(10));
    39. /**
    40. * 有返回值,有多个参数
    41. */
    42. ReturnMultiParam returnMultiParam = (int a ,int b)->{
    43. System.out.print("ReturnMultiParam ");
    44. return a+b;
    45. };
    46. System.out.println(returnMultiParam.method(10, 20));
    47. }

    Lambda语法简化

    1. /**
    2. * 无返回值,无参数
    3. */
    4. /* NoReturnNoParam noReturnNoParam = ()->{ System.out.println("NoReturnNoParam");
    5. };*/
    6. /**
    7. * 简化版
    8. */
    9. NoReturnNoParam noReturnNoParam = ()-> System.out.println("NoReturnNoParam");
    10. noReturnNoParam.method();
    11. /**
    12. * 无返回值,有一个参数
    13. */
    14. /* NoReturnOneParam noReturnOneParam = (int a)->{
    15. System.out.println("NoReturnOneParam "+a);
    16. };*/
    17. /**
    18. * 简化版
    19. */
    20. NoReturnOneParam noReturnOneParam = a -> System.out.println("NoReturnOneParam "+a);
    21. noReturnOneParam.method(10);
    22. /**
    23. * 无返回值,有多个参数
    24. */
    25. /* NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
    26. System.out.println("NoReturnMultiParam "+a+"\t"+b);
    27. };*/
    28. NoReturnMultiParam noReturnMultiParam = (a,b)-> System.out.println("NoReturnMultiParam "+a+"\t"+b);
    29. noReturnMultiParam.method(10,20);
    30. /**
    31. * 有返回值,无参数
    32. */
    33. /* ReturnNoParam returnNoParam = ()->{
    34. System.out.print("ReturnNoParam ");
    35. return 10;
    36. };*/
    37. /**
    38. * 简化版
    39. */
    40. ReturnNoParam returnNoParam = ()->10+20;
    41. System.out.println(returnNoParam.method());
    42. /**
    43. * 有返回值,有一个参数
    44. */
    45. /* ReturnOneParam returnOneParam = (int a)->
    46. {
    47. System.out.print("ReturnOneParam ");
    48. return a;
    49. };*/
    50. /***
    51. * 简化版
    52. */
    53. ReturnOneParam returnOneParam = a->a;
    54. System.out.println(returnOneParam.method(10));
    55. /**
    56. * 有返回值,有多个参数
    57. */
    58. /*ReturnMultiParam returnMultiParam = (int a ,int b)->{
    59. System.out.print("ReturnMultiParam ");
    60. return a+b;
    61. };*/
    62. /**
    63. * 简化版
    64. */
    65. ReturnMultiParam returnMultiParam = (a ,b)- >a+b;
    66. System.out.println(returnMultiParam.method(10, 20));
    67. }

    Lambda表达式的使用

    Lambda表达式引用方法

    有时候我们不是必须使用Lambda的函数体定义实现,我们可以利 用 lambda表达式指向一个已经存在的方法作为抽象方法的实现。

     要求

       1、参数的个数以及类型需要与函数接口中的抽象方法一致。

       2、返回值类型要与函数接口中的抽象方法的返回值类型一致。

    语法 

          方法归属者::方法名 静态方法的归属者为类名,非静态方法归属者 为该对象的引用。

    案例

    1. /**
    2. * 无返回值,无参数
    3. */
    4. @FunctionalInterface
    5. interface NoReturnNoParam{
    6. void method();
    7. }
    8. /**
    9. * 无返回值,有一个参数
    10. */
    11. @FunctionalInterface
    12. interface NoReturnOneParam{
    13. void method(int a);
    14. }
    15. /**
    16. * 无返回值,有多个参数
    17. */
    18. @FunctionalInterface
    19. interface NoReturnMultiParam{
    20. void method(int a,int b);
    21. }
    22. /**
    23. * 有返回值,无参数
    24. */
    25. @FunctionalInterface
    26. interface ReturnNoParam{
    27. int method();
    28. }
    29. /**
    30. * 有返回值,有一个参数
    31. */
    32. @FunctionalInterface
    33. interface ReturnOneParam{
    34. int method(int a);
    35. }
    36. /**
    37. * 有返回值,有多个参数
    38. */
    39. @FunctionalInterface
    40. interface ReturnMultiParam{
    41. int method(int a,int b);
    42. }
    43. public class Test {
    44. public static void main(String[] args) {
    45. /**
    46. * 无返回值,无参数
    47. */
    48. /* NoReturnNoParam noReturnNoParam = ()->{
    49. System.out.println("NoReturnNoParam");};*/
    50. /**
    51. * 简化版
    52. */
    53. NoReturnNoParam noReturnNoParam = ()-> System.out.println("NoReturnNoParam");
    54. noReturnNoParam.method();
    55. /**
    56. * 无返回值,有一个参数
    57. */
    58. /* NoReturnOneParam noReturnOneParam =(int a)->{
    59. System.out.println("NoReturnOneParam "+a);
    60. };*/
    61. /**
    62. * 简化版
    63. */
    64. NoReturnOneParam noReturnOneParam = a -> System.out.println("NoReturnOneParam"+a);
    65. noReturnOneParam.method(10);
    66. /**
    67. * 无返回值,有多个参数
    68. */
    69. /* NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
    70. System.out.println("NoReturnMultiParam"+a+"\t"+b);
    71. };*/
    72. NoReturnMultiParam noReturnMultiParam = (a,b)-> System.out.println("NoReturnMultiParam"+a+"\t"+b);
    73. noReturnMultiParam.method(10,20);
    74. /**
    75. * 有返回值,无参数
    76. */
    77. /* ReturnNoParam returnNoParam = ()->{
    78. System.out.print("ReturnNoParam ");
    79. return 10;
    80. };*/
    81. /**
    82. * 简化版
    83. */
    84. ReturnNoParam returnNoParam = ()->10+20;
    85. System.out.println(returnNoParam.method());
    86. /**
    87. * 有返回值,有一个参数
    88. */
    89. /* ReturnOneParam returnOneParam = (inta)->{
    90. System.out.print("ReturnOneParam");
    91. return a;
    92. };*/
    93. /***
    94. * 简化版
    95. */
    96. ReturnOneParam returnOneParam = a->a;
    97. System.out.println(returnOneParam.method(10));
    98. /**
    99. * 有返回值,有多个参数
    100. */
    101. /*ReturnMultiParam returnMultiParam = (int a ,int b)->{
    102. System.out.print("ReturnMultiParam");
    103. return a+b;
    104. };*/
    105. /**
    106. * 简化版
    107. */
    108. ReturnMultiParam returnMultiParam = (a,b)->a+b;
    109. System.out.println(returnMultiParam.method(10,20));
    110. }
    111. /**
    112. * 要求:
    113. * 1,参数的个数以及类型需要与函数接口中的抽象方法一致。
    114. * 2,返回值类型要与函数接口中的抽象方法的返回值类型一致。
    115. * @param a
    116. * @return
    117. */
    118. public static int doubleNum(int a){
    119. return 2*a;
    120. }
    121. public int addTwo(int a){
    122. return a+2;
    123. }
    124. }
    1. public class Test2 {
    2. public static void main(String[] args) {
    3. ReturnOneParam returnOneParam =Test::doubleNum;
    4. int value = returnOneParam.method(10);
    5. System.out.println(value);
    6. Test test = new Test();
    7. ReturnOneParam returnOneParam1 = test::addTwo;
    8. int value2 = returnOneParam1.method(10);
    9. System.out.println(value2);
    10. }
    11. }

    Lambda表达式创建线程

    1. public class Test3 {
    2. public static void main(String[] args) {
    3. System.out.println(Thread.currentThread().getName()+" 开始");
    4. new Thread(()->{
    5. for(int i=0;i<20;i++){
    6. try {
    7. Thread.sleep(500);
    8. } catch (InterruptedExceptione) {
    9. e.printStackTrace();
    10. }
    11. System.out.println(Thread.currentThread().getName()+" "+i);
    12. }
    13. },"Lambda Thread ").start();
    14. System.out.println(Thread.currentThread().getName()+" 结束");
    15. }
    16. }

    Lambda 表达式中的闭包问题

    什么是闭包

    闭包的本质就是代码片断。所以闭包可以理解成一个代码片断的引 用。在Java中匿名内部类也是闭包的一种实现方式。 在闭包中访问外部的变量时,外部变量必须是final类型,虚拟机会 帮我们加上 final 修饰关键字。

    1. public class Test4 {
    2. public static void main(String[] args) {
    3. final int num =10;
    4. NoReturnNoParam noReturnNoParam = ()- >System.out.println(num);
    5. noReturnNoParam.method();
    6. }
    7. }

    常用的函数接口

    Consumer接口的使用

    Consumer 接口是JDK为我们提供的一个函数式接口,该接口也被 称为消费型接口。

     遍历集合

    我们可以调用集合的 public void forEach(Consumer action) 方法,通过 lambda 表达式的方式遍历集合中的元素。以下 是 Consumer 接口的方法以及遍历集合的操作。

    1. public class Test4 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("a");
    5. list.add("b");
    6. list.add("c");
    7. list.add("d");
    8. list.forEach(System.out::println);
    9. }
    10. }

    Predicate接口的使用

    Predicate 是 JDK 为我们提供的一个函数式接口,可以简化程序的编写。

     删除集合中的元素

    我们通过public boolean removeIf(Predicate filter)方 法来删除集合中的某个元素,

    1. public class Test5 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("a");
    5. list.add("b");
    6. list.add("c");
    7. list.add("d");
    8. list.removeIf(ele->ele.equals("b"));
    9. list.forEach(System.out::println);
    10. }
    11. }

    Comparator接口的使用

    Comparator是 JDK 为我们提供的一个函数式接口,该接口为比较 器接口。

    元素排序

    之前我们若要为集合内的元素排序,就必须调用 sort 方法,传入比 较器重写 compare 方法的比较器对象,现在我们还可以使用 lambda 表达式来简化代码。

    1. public class Test7 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("a");
    5. list.add("d");
    6. list.add("b");
    7. list.add("c");
    8. list.sort((o1,o2)->o1.compareTo(o2));
    9. list.forEach(System.out::println);
    10. }
    11. }

     Stream流介绍

    Stream流简介

    Stream是数据渠道,用于操作数据源所生成的元素序列,它可以实 现对集合的复杂操作,例如过滤、排序和映射等。Stream不会改变 源对象,而是返回一个新的结果集。

     Stream流的生成方式

    生成流:通过数据源(集合、数组等)创建一个流。

    中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数 据过滤/映射,然后返回一个新的流,交给下一个操作使用。

    终结操作:一旦执行终止操作,就执行中间的链式操作,并产生结果。

    Stream流的常见方法 

    数据过滤

    1. public class Test8 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("oldlu");
    5. list.add("oldlin");
    6. list.add("kevin");
    7. list.add("peter");
    8. //多条件and关系
    9. list.stream().filter(ele -> ele.startsWith("o")).filter(ele-
    10. >ele.endsWith("n")).collect(Collectors.toList()).forEach(System.out::println);
    11. System.out.println("------------------------");
    12. //多条件or关系
    13. Predicate<String> predicate1 = ele ->ele.startsWith("o");
    14. Predicate<String> predicate2 = ele->ele.endsWith("n");
    15. list.stream().filter(predicate1.or(predicate2)
    16. ).collect(Collectors.toList()).forEach(System.out::println);
    17. }
    18. }

    数量限制

    1. public class Test9 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("oldlu");
    5. list.add("oldlin");
    6. list.add("kevin");
    7. list.add("peter");
    8. //limit
    9. list.stream().limit(2).forEach(System.out::println);
    10. }
    11. }

    元素排序

    1. public class Test10 {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("b");
    5. list.add("c");
    6. list.add("a");
    7. list.add("d");
    8. //升序排序
    9. list.stream().sorted(Comparator.naturalOrder()).forEach(System.out::println);
    10. System.out.println("---------------");
    11. //降序排序
    12. list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
    13. }
    14. }

  • 相关阅读:
    一、vue介绍
    【计算机组成原理】寄存器的本质——锁存器
    Visual studio代码提示(IntelliSense)的语言(包括汉化等)修改
    【paddle】Vision Transformer(attention)
    LeetCode数据流的第 K 大数值
    基础:types of keys
    代码随想录训练营第III期--018--python
    马斯克440亿美元收购Twitter一年后:全力“下云”,成本速降60%,功能代码从70万行减少至7万!...
    如何在vi编辑器中复制内容到终端
    Mendix中的依赖管理:npm和Maven的应用
  • 原文地址:https://blog.csdn.net/m0_58719994/article/details/127976805