更新時間:2022-08-25 來源:黑馬程序員 瀏覽量:
概述
官網對lambda表達式的描述
> 官網: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.
匿名類的一個問題是,如果匿名類的實現非常簡單,例如只包含一個方法的接口,那么匿名類的語法可能會顯得笨拙和不清楚。在這些情況下,您通常會嘗試將功能作為參數傳遞給另一個方法,例如當有人單擊按鈕時應該采取什么操作。 Lambda 表達式使您能夠做到這一點,將功能視為方法參數,或將代碼視為數據。
> 描述中包含了三層含義
- lambda表達式是對匿名類的簡化
- lambda使用的前提
- 一個接口
- 接口中包含一個方法
- lambda表達式的理解:將功能作為參數傳遞給另一個方法
示例代碼
- 創建并開啟一個線程,使用匿名內部類的方式實現Runnable,重寫run方法
public static void main(String[] args) { new Thread(new Runnable() { // 匿名內部類 @Override public void run() { System.out.println("我是線程開啟執行的代碼"); } }).start(); } ```
- Runnable接口中只有一個抽象方法run。用lambda表達式改寫
// @FunctionalInterface // public interface Runnable { // public abstract void run(); // } public static void main(String[] args) { new Thread(() -> System.out.println("我是線程開啟執行的代碼")).start(); } ```
語法
基本語法
> 從上述案例中,使用lambda表達式是對Runnable接口中的run方法進行了重寫
>
> 格式:(抽象方法的參數列表) -> {重寫的代碼}
示例代碼
> 刪除集合中大于3的元素
- 匿名內部類
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表達式
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] ```
- 說明
簡寫語法
> 參數的簡寫
> 參數的簡寫 > > - 抽象方法參數的個數 > - 空參:不省略。 > - 一個參數:省略<span style="color:red;">小括號</span>,省略<span style="color:red;">參數類型</span>。 > - 省略前:(Integer i) -> {} > - 省略后:i -> {} > - 多個參數:省略<span style="color:red;">參數類型</span>。 > - 省略前:(String a, Integer b) -> {} > - 省略后: (a,b) -> {} > > 方法體的簡寫 > > - 方法體中只有一行表達式:省略<span style="color:red;">大括號、return、分號</span>。 > - 省略前:(Integer i) -> {return i > 3;} > - 省略后:i -> i > 3
示例代碼
- lambda表達式
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] ```
- 簡寫
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調試
- Demo.java
public class Demo { public static void main(String[] args) { new Thread(() -> { System.out.println("我是線程啟動后執行的代碼"); }).start(); } } ```
- debug運行
- 說明
- run:748,Thread(java.lang):調用Thread中的run方法
- run:-1,1156060786(`org.example.Demo$$Lambda$1`):調用`Demo$$Lambda$1`中的run方法
- `lambda$main$0:10`,Demo(org.example): 方法`lambda$main$0`中執行了 打印語句
- 小結
- `Demo$$Lambda$1`這個類中的run方法 調用 -----> `lambda$main$0`方法 -------> 執行 lambda表達式代碼塊的代碼(打印語句)
保留lambda語句產生的字節碼文件
- java命令+參數。在硬盤中產生一個新的class文件(Demo$$Lambda$1.class)
java -Djdk.internal.lambda.dumpProxyClasses Demo.class ```
- 將該文件拖入的idea中
- `Demo$$Lambda$1`是Runnable的實現類
- run方法中調用`Demo.lambda$main$0()`方法
原理理解
方法引用(Method references)
概述
官網對方法引用的描述
> 官網: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 表達式來創建匿名方法。然而,有時 lambda 表達式除了調用現有方法之外什么都不做。在這些情況下,按名稱引用現有方法通常會更清楚。方法引用使您能夠做到這一點;它們是用于已具有名稱的方法的緊湊、易于閱讀的 lambda 表達式。
> 描述中包含兩層含義
>
> - 方法引用,用于labmda表達式中
> - 前提:lambda 表達式除了調用現有方法之外什么都不做。(下一節語法中的案例進行說明)
> - lambda表達式中的參數調用方法
> - 示例:(String s) -> s.toLowerCase()
> - labmda表達式中的參數作為其他方法的參數
> - 示例:(Ineger i) -> String.valueOf(i)
語法
> 官網: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` |
四種方法引用
| 種類 | 語法 | 示例 |
| ------------------------------------ | ------------------ | ------------------------------------------------------------ |
| 引用靜態方法 | `類名::靜態方法名` | `Person::compareByAge` `MethodReferencesExamples::appendStrings` |
| 對特定對象的實例方法的引用 | `對象名::方法名` | `myComparisonProvider::compareByName` `myApp::appendStrings2` |
| 對特定類型的任意對象的實例方法的引用 | `類名::方法名` | `String::compareToIgnoreCase` `String::concat` |
| 引用構造方法 | `類名::new` | `HashSet::new` |
下面的案例中會用到Stream相關API,我們會在后續的文章中進行詳細討論。
下面的案例中會用到Stream相關API,我們會在后續的文章中進行詳細討論。
- 引用靜態方法
// 將集合中的Integer 轉換為 String, 并收集到一個新的集合中 List<Integer> integerList = new ArrayList<>(Arrays.asList(1,2,3,4,5)); List<String> stringList = integerList.stream() // 參數i 作為String靜態方法valueOf的參數。并且lambda表達式中除了方法的調用以外其他什么都沒做 // .map(i -> String.valueOf(i)) .map(String::valueOf) // 引用String類中的靜態方法valueOf。類名::靜態方法名 .collect(Collectors.toList()); System.out.println(stringList); ```
- 對特定對象的實例方法的引用
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.與靜態方法不同,要想使用Test類中的show方法 需要先有Test類的實例 2.參數i 作為test對象show方法的參數 3.并且lambda表達式中除了方法的調用以外其他什么都沒做 */ // .forEach(i -> test.show(i)); .forEach(test::show); // 引用test對象中的方法show。對象名::方法名 } } class Test{ public void show(Object o){ System.out.println(o); } } ```
- 對特定類型的任意對象的實例方法的引用
// 將集合中的元素轉成大寫,并收集到新的集合中 List<String> list = new ArrayList<>(Arrays.asList("a","b","c")); List<String> list2 = list.stream() /* 1.參數s 作為toUpperCase方法的調用者 2.并且lambda表達式中除了方法的調用以外其他什么都沒做 3.引用的類型為參數s的數據類型String */ // .map(s -> s.toUpperCase()) .map(String::toUpperCase) // 引用String類中的方法toUpperCase。類名::方法名 .collect(Collectors.toList()); ```
- 引用構造方法
// 將集合中的元素轉成Person對象,并收集到新的集合中 public class Demo { public static void main(String[] args) { List<String> stringList = new ArrayList<>(Arrays.asList("張三","李四","王五")); List<Person> personList = stringList.stream() /* 1.參數s 作為Person類構造方法的參數 2.并且lambda表達式中除了方法的調用以外其他什么都沒做 */ // .map(s -> new Person(s)) .map(Person::new) // 引用Person類中的構造方法。類名::new .collect(Collectors.toList()); } } class Person{ private String name; public Person(String name) { this.name = name; } } ```