首頁(yè)技術(shù)文章正文

Java培訓(xùn):Lambda表達(dá)式

更新時(shí)間:2022-08-25 來(lái)源:黑馬程序員 瀏覽量:

  概述

  官網(wǎng)對(duì)lambda表達(dá)式的描述

  > 官網(wǎng):https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

   One issue with anonymous classes is that if the implementation of your anonymous class is very simple, such as an interface that contains only one method, then the syntax of anonymous classes may seem unwieldy and unclear. In these cases, you're usually trying to pass functionality as an argument to another method, such as what action should be taken when someone clicks a button. Lambda expressions enable you to do this, to treat functionality as method argument, or code as data.

   匿名類的一個(gè)問(wèn)題是,如果匿名類的實(shí)現(xiàn)非常簡(jiǎn)單,例如只包含一個(gè)方法的接口,那么匿名類的語(yǔ)法可能會(huì)顯得笨拙和不清楚。在這些情況下,您通常會(huì)嘗試將功能作為參數(shù)傳遞給另一個(gè)方法,例如當(dāng)有人單擊按鈕時(shí)應(yīng)該采取什么操作。 Lambda 表達(dá)式使您能夠做到這一點(diǎn),將功能視為方法參數(shù),或?qū)⒋a視為數(shù)據(jù)。

  > 描述中包含了三層含義

  - lambda表達(dá)式是對(duì)匿名類的簡(jiǎn)化

  - lambda使用的前提

  - 一個(gè)接口

  - 接口中包含一個(gè)方法

  - lambda表達(dá)式的理解:將功能作為參數(shù)傳遞給另一個(gè)方法

  示例代碼

  - 創(chuàng)建并開(kāi)啟一個(gè)線程,使用匿名內(nèi)部類的方式實(shí)現(xiàn)Runnable,重寫(xiě)run方法

public static void main(String[] args) {
      new Thread(new Runnable() { // 匿名內(nèi)部類
          @Override
          public void run() {
              System.out.println("我是線程開(kāi)啟執(zhí)行的代碼");
          }
      }).start();
  }
  ```

  - Runnable接口中只有一個(gè)抽象方法run。用lambda表達(dá)式改寫(xiě)

  // @FunctionalInterface
  // public interface Runnable {
  //    public abstract void run();
  // }
  public static void main(String[] args) {
      new Thread(() -> System.out.println("我是線程開(kāi)啟執(zhí)行的代碼")).start();
  }
  ```

  語(yǔ)法

  基本語(yǔ)法

  > 從上述案例中,使用lambda表達(dá)式是對(duì)Runnable接口中的run方法進(jìn)行了重寫(xiě)

  >

  > 格式:(抽象方法的參數(shù)列表) -> {重寫(xiě)的代碼}

  示例代碼

  > 刪除集合中大于3的元素

  - 匿名內(nèi)部類

  List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
  list.removeIf(new Predicate<Integer>() {
      @Override
      public boolean test(Integer i) {
          return i > 3;
      }
  });
  System.out.println(list); // [1, 2, 3]
  ```

  - lambda表達(dá)式

  List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
  list.removeIf((Integer i) -> {return i > 3;});
  System.out.println(list); // [1, 2, 3]
  ```

  - 說(shuō)明

1661396339740_1.jpg

  簡(jiǎn)寫(xiě)語(yǔ)法

  > 參數(shù)的簡(jiǎn)寫(xiě)

> 參數(shù)的簡(jiǎn)寫(xiě)
>
> - 抽象方法參數(shù)的個(gè)數(shù)
>   - 空參:不省略。
>   - 一個(gè)參數(shù):省略<span style="color:red;">小括號(hào)</span>,省略<span style="color:red;">參數(shù)類型</span>。
>     - 省略前:(Integer i) -> {}
>     - 省略后:i -> {}
>   - 多個(gè)參數(shù):省略<span style="color:red;">參數(shù)類型</span>。
>     - 省略前:(String a, Integer b) -> {}
>     - 省略后: (a,b) -> {}
>
> 方法體的簡(jiǎn)寫(xiě)
>
> - 方法體中只有一行表達(dá)式:省略<span style="color:red;">大括號(hào)、return、分號(hào)</span>。
>   - 省略前:(Integer i) -> {return i > 3;}
>   - 省略后:i -> i > 3

  示例代碼

  - lambda表達(dá)式

  List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
  list.removeIf((Integer i) -> {return i > 3;});
  System.out.println(list); // [1, 2, 3]
  ```

  - 簡(jiǎn)寫(xiě)

  List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
  list.removeIf(i -> i > 3);
  System.out.println(list); // [1, 2, 3]
  ```

  原理

  debug調(diào)試

  - Demo.java

  public class Demo {
      public static void main(String[] args) {
          new Thread(() -> {
              System.out.println("我是線程啟動(dòng)后執(zhí)行的代碼");
          }).start();
      }
  }
  ```

  - debug運(yùn)行

1661396506923_2.jpg

  - 說(shuō)明

  - run:748,Thread(java.lang):調(diào)用Thread中的run方法

  - run:-1,1156060786(`org.example.Demo$$Lambda$1`):調(diào)用`Demo$$Lambda$1`中的run方法

  - `lambda$main$0:10`,Demo(org.example): 方法`lambda$main$0`中執(zhí)行了 打印語(yǔ)句

  - 小結(jié)

  - `Demo$$Lambda$1`這個(gè)類中的run方法 調(diào)用 -----> `lambda$main$0`方法 -------> 執(zhí)行 lambda表達(dá)式代碼塊的代碼(打印語(yǔ)句)

  保留lambda語(yǔ)句產(chǎn)生的字節(jié)碼文件

  - java命令+參數(shù)。在硬盤(pán)中產(chǎn)生一個(gè)新的class文件(Demo$$Lambda$1.class)

  java -Djdk.internal.lambda.dumpProxyClasses Demo.class
  ```

  

1661396614524_3.jpg

  - 將該文件拖入的idea中

  - `Demo$$Lambda$1`是Runnable的實(shí)現(xiàn)類

  - run方法中調(diào)用`Demo.lambda$main$0()`方法

1661396713546_4.jpg

  原理理解

1661396750319_5.jpg

  方法引用(Method references)

  概述

  官網(wǎng)對(duì)方法引用的描述

  > 官網(wǎng):https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

   You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

   您可以使用 lambda 表達(dá)式來(lái)創(chuàng)建匿名方法。然而,有時(shí) lambda 表達(dá)式除了調(diào)用現(xiàn)有方法之外什么都不做。在這些情況下,按名稱引用現(xiàn)有方法通常會(huì)更清楚。方法引用使您能夠做到這一點(diǎn);它們是用于已具有名稱的方法的緊湊、易于閱讀的 lambda 表達(dá)式。

  > 描述中包含兩層含義

  >

  > - 方法引用,用于labmda表達(dá)式中

  > - 前提:lambda 表達(dá)式除了調(diào)用現(xiàn)有方法之外什么都不做。(下一節(jié)語(yǔ)法中的案例進(jìn)行說(shuō)明)

  > - lambda表達(dá)式中的參數(shù)調(diào)用方法

  > - 示例:(String s) -> s.toLowerCase()

  > - labmda表達(dá)式中的參數(shù)作為其他方法的參數(shù)

  > - 示例:(Ineger i) -> String.valueOf(i)

  語(yǔ)法

  > 官網(wǎng):https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

  There are four kinds of method references:

  | Kind | Syntax | Examples |

  | ------------------------------------------------------------ | -------------------------------------- | ------------------------------------------------------------ |

  | Reference to a static method | `ContainingClass::staticMethodName` | `Person::compareByAge` `MethodReferencesExamples::appendStrings` |

  | Reference to an instance method of a particular object | `containingObject::instanceMethodName` | `myComparisonProvider::compareByName` `myApp::appendStrings2` |

  | Reference to an instance method of an arbitrary object of a particular type | `ContainingType::methodName` | `String::compareToIgnoreCase` `String::concat` |

  | Reference to a constructor | `ClassName::new` | `HashSet::new` |

  四種方法引用

  | 種類 | 語(yǔ)法 | 示例 |

  | ------------------------------------ | ------------------ | ------------------------------------------------------------ |

  | 引用靜態(tài)方法 | `類名::靜態(tài)方法名` | `Person::compareByAge` `MethodReferencesExamples::appendStrings` |

  | 對(duì)特定對(duì)象的實(shí)例方法的引用 | `對(duì)象名::方法名` | `myComparisonProvider::compareByName` `myApp::appendStrings2` |

  | 對(duì)特定類型的任意對(duì)象的實(shí)例方法的引用 | `類名::方法名` | `String::compareToIgnoreCase` `String::concat` |

  | 引用構(gòu)造方法 | `類名::new` | `HashSet::new` |

  下面的案例中會(huì)用到Stream相關(guān)API,我們會(huì)在后續(xù)的文章中進(jìn)行詳細(xì)討論。

  下面的案例中會(huì)用到Stream相關(guān)API,我們會(huì)在后續(xù)的文章中進(jìn)行詳細(xì)討論。

  - 引用靜態(tài)方法

  // 將集合中的Integer 轉(zhuǎn)換為 String, 并收集到一個(gè)新的集合中
  List<Integer> integerList = new ArrayList<>(Arrays.asList(1,2,3,4,5));
  List<String> stringList = integerList.stream()
      // 參數(shù)i 作為String靜態(tài)方法valueOf的參數(shù)。并且lambda表達(dá)式中除了方法的調(diào)用以外其他什么都沒(méi)做
      // .map(i -> String.valueOf(i))
      .map(String::valueOf) // 引用String類中的靜態(tài)方法valueOf。類名::靜態(tài)方法名
      .collect(Collectors.toList());
  System.out.println(stringList);
  ```

  - 對(duì)特定對(duì)象的實(shí)例方法的引用

  public class Demo {
      public static void main(String[] args) {
          Test test = new Test();
          List<Integer> integerList = new ArrayList<>(Arrays.asList(1,2,3,4,5));
          integerList.stream()
                  /*
                      1.與靜態(tài)方法不同,要想使用Test類中的show方法 需要先有Test類的實(shí)例
                      2.參數(shù)i 作為test對(duì)象show方法的參數(shù)
                      3.并且lambda表達(dá)式中除了方法的調(diào)用以外其他什么都沒(méi)做
                   */
                  // .forEach(i -> test.show(i));
                  .forEach(test::show); // 引用test對(duì)象中的方法show。對(duì)象名::方法名
      }
  }
 
  class Test{
      public void show(Object o){
          System.out.println(o);
      }
  }
  ```

  - 對(duì)特定類型的任意對(duì)象的實(shí)例方法的引用

  // 將集合中的元素轉(zhuǎn)成大寫(xiě),并收集到新的集合中
  List<String> list = new ArrayList<>(Arrays.asList("a","b","c"));
  List<String> list2 = list.stream()
      /*
         1.參數(shù)s 作為toUpperCase方法的調(diào)用者
         2.并且lambda表達(dá)式中除了方法的調(diào)用以外其他什么都沒(méi)做
         3.引用的類型為參數(shù)s的數(shù)據(jù)類型String
      */
      // .map(s -> s.toUpperCase())
      .map(String::toUpperCase) // 引用String類中的方法toUpperCase。類名::方法名
      .collect(Collectors.toList());
  ```

  - 引用構(gòu)造方法

  // 將集合中的元素轉(zhuǎn)成Person對(duì)象,并收集到新的集合中
  public class Demo {
      public static void main(String[] args) {
          List<String> stringList = new ArrayList<>(Arrays.asList("張三","李四","王五"));
 
          List<Person> personList = stringList.stream()
                  /*
                      1.參數(shù)s 作為Person類構(gòu)造方法的參數(shù)
                      2.并且lambda表達(dá)式中除了方法的調(diào)用以外其他什么都沒(méi)做
                   */
                  // .map(s -> new Person(s))
                  .map(Person::new) // 引用Person類中的構(gòu)造方法。類名::new
                  .collect(Collectors.toList());
      }
  }
 
  class Person{
      private String name;
 
      public Person(String name) {
          this.name = name;
      }
  }
  ```


分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!