Java-基礎語法20:Lambda&方法引用
1.Lambda表示式
1.1體驗Lambda表示式【理解】
-
案例需求
啟動一個執行緒,在控制檯輸出一句話:多執行緒程式啟動了
-
實現方式一
- 實現步驟
- 定義一個類MyRunnable實現Runnable介面,重寫run()方法
- 建立MyRunnable類的物件
- 建立Thread類的物件,把MyRunnable的物件作為構造引數傳遞
- 啟動執行緒
- 實現步驟
-
實現方式二
- 匿名內部類的方式改進
-
實現方式三
- Lambda表示式的方式改進
-
程式碼演示
//方式一的執行緒類 public class MyRunnable implements Runnable { @Override public void run() { System.out.println("多執行緒程式啟動了"); } } public class LambdaDemo { public static void main(String[] args) { //方式一 // MyRunnable my = new MyRunnable(); // Thread t = new Thread(my); // t.start(); //方式二 // new Thread(new Runnable() { // @Override // public void run() { // System.out.println("多執行緒程式啟動了"); // } // }).start(); //方式三 new Thread( () -> { System.out.println("多執行緒程式啟動了"); } ).start(); } }
-
函數語言程式設計思想概述
函式式思想則儘量忽略物件導向的複雜語法:“強調做什麼,而不是以什麼形式去做”
而我們要學習的Lambda表示式就是函式式思想的體現
1.2Lambda表示式的標準格式【理解】
-
格式:
(形式引數) -> {程式碼塊}
-
形式引數:如果有多個引數,引數之間用逗號隔開;如果沒有引數,留空即可
-
->:由英文中畫線和大於符號組成,固定寫法。代表指向動作
-
程式碼塊:是我們具體要做的事情,也就是以前我們寫的方法體內容
-
-
組成Lambda表示式的三要素:
- 形式引數,箭頭,程式碼塊
1.3Lambda表示式練習1【應用】
-
Lambda表示式的使用前提
-
有一個介面
-
介面中有且僅有一個抽象方法
-
-
練習描述
無參無返回值抽象方法的練習
-
操作步驟
-
定義一個介面(Eatable),裡面定義一個抽象方法:void eat();
-
定義一個測試類(EatableDemo),在測試類中提供兩個方法
-
一個方法是:useEatable(Eatable e)
-
一個方法是主方法,在主方法中呼叫useEatable方法
-
-
-
示例程式碼
//介面 public interface Eatable { void eat(); } //實現類 public class EatableImpl implements Eatable { @Override public void eat() { System.out.println("一天一蘋果,醫生遠離我"); } } //測試類 public class EatableDemo { public static void main(String[] args) { //在主方法中呼叫useEatable方法 Eatable e = new EatableImpl(); useEatable(e); //匿名內部類 useEatable(new Eatable() { @Override public void eat() { System.out.println("一天一蘋果,醫生遠離我"); } }); //Lambda表示式 useEatable(() -> { System.out.println("一天一蘋果,醫生遠離我"); }); } private static void useEatable(Eatable e) { e.eat(); } }
1.4Lambda表示式練習2【應用】
-
練習描述
有參無返回值抽象方法的練習
-
操作步驟
-
定義一個介面(Flyable),裡面定義一個抽象方法:void fly(String s);
-
定義一個測試類(FlyableDemo),在測試類中提供兩個方法
-
一個方法是:useFlyable(Flyable f)
-
一個方法是主方法,在主方法中呼叫useFlyable方法
-
-
-
示例程式碼
public interface Flyable { void fly(String s); } public class FlyableDemo { public static void main(String[] args) { //在主方法中呼叫useFlyable方法 //匿名內部類 useFlyable(new Flyable() { @Override public void fly(String s) { System.out.println(s); System.out.println("飛機自駕遊"); } }); System.out.println("--------"); //Lambda useFlyable((String s) -> { System.out.println(s); System.out.println("飛機自駕遊"); }); } private static void useFlyable(Flyable f) { f.fly("風和日麗,晴空萬里"); } }
1.5Lambda表示式練習3【應用】
-
練習描述
有參有返回值抽象方法的練習
-
操作步驟
-
定義一個介面(Addable),裡面定義一個抽象方法:int add(int x,int y);
-
定義一個測試類(AddableDemo),在測試類中提供兩個方法
-
一個方法是:useAddable(Addable a)
-
一個方法是主方法,在主方法中呼叫useAddable方法
-
-
-
示例程式碼
public interface Addable { int add(int x,int y); } public class AddableDemo { public static void main(String[] args) { //在主方法中呼叫useAddable方法 useAddable((int x,int y) -> { return x + y; }); } private static void useAddable(Addable a) { int sum = a.add(10, 20); System.out.println(sum); } }
1.6Lambda表示式的省略模式【應用】
-
省略的規則
- 引數型別可以省略。但是有多個引數的情況下,不能只省略一個
- 如果引數有且僅有一個,那麼小括號可以省略
- 如果程式碼塊的語句只有一條,可以省略大括號和分號,和return關鍵字
-
程式碼演示
public interface Addable { int add(int x, int y); } public interface Flyable { void fly(String s); } public class LambdaDemo { public static void main(String[] args) { // useAddable((int x,int y) -> { // return x + y; // }); //引數的型別可以省略 useAddable((x, y) -> { return x + y; }); // useFlyable((String s) -> { // System.out.println(s); // }); //如果引數有且僅有一個,那麼小括號可以省略 // useFlyable(s -> { // System.out.println(s); // }); //如果程式碼塊的語句只有一條,可以省略大括號和分號 useFlyable(s -> System.out.println(s)); //如果程式碼塊的語句只有一條,可以省略大括號和分號,如果有return,return也要省略掉 useAddable((x, y) -> x + y); } private static void useFlyable(Flyable f) { f.fly("風和日麗,晴空萬里"); } private static void useAddable(Addable a) { int sum = a.add(10, 20); System.out.println(sum); } }
1.7Lambda表示式的注意事項【理解】
-
使用Lambda必須要有介面,並且要求介面中有且僅有一個抽象方法
-
必須有上下文環境,才能推匯出Lambda對應的介面
-
根據區域性變數的賦值得知Lambda對應的介面
Runnable r = () -> System.out.println(“Lambda表示式”);
-
根據呼叫方法的引數得知Lambda對應的介面
new Thread(() -> System.out.println(“Lambda表示式”)).start();
-
1.8Lambda表示式和匿名內部類的區別【理解】
-
所需型別不同
- 匿名內部類:可以是介面,也可以是抽象類,還可以是具體類
- Lambda表示式:只能是介面
-
使用限制不同
-
如果介面中有且僅有一個抽象方法,可以使用Lambda表示式,也可以使用匿名內部類
-
如果介面中多於一個抽象方法,只能使用匿名內部類,而不能使用Lambda表示式
-
-
實現原理不同
- 匿名內部類:編譯之後,產生一個單獨的.class位元組碼檔案
- Lambda表示式:編譯之後,沒有一個單獨的.class位元組碼檔案。對應的位元組碼會在執行的時候動態生成
2.介面組成更新
2.1介面組成更新概述【理解】
-
常量
public static final
-
抽象方法
public abstract
-
預設方法(Java 8)
-
靜態方法(Java 8)
-
私有方法(Java 9)
2.2介面中預設方法【應用】
-
格式
public default 返回值型別 方法名(引數列表) { }
-
範例
public default void show3() { }
-
注意事項
-
預設方法不是抽象方法,所以不強制被重寫。但是可以被重寫,重寫的時候去掉default關鍵字
-
public可以省略,default不能省略
-
2.3介面中靜態方法【應用】
-
格式
public static 返回值型別 方法名(引數列表) { }
-
範例
public static void show() { }
-
注意事項
-
靜態方法只能通過介面名呼叫,不能通過實現類名或者物件名呼叫
-
public可以省略,static不能省略
-
2.4介面中私有方法【應用】
-
私有方法產生原因
Java 9中新增了帶方法體的私有方法,這其實在Java 8中就埋下了伏筆:Java 8允許在介面中定義帶方法體的預設方法和靜態方法。這樣可能就會引發一個問題:當兩個預設方法或者靜態方法中包含一段相同的程式碼實現時,程式必然考慮將這段實現程式碼抽取成一個共性方法,而這個共性方法是不需要讓別人使用的,因此用私有給隱藏起來,這就是Java 9增加私有方法的必然性
-
定義格式
-
格式1
private 返回值型別 方法名(引數列表) { }
-
範例1
private void show() { }
-
格式2
private static 返回值型別 方法名(引數列表) { }
-
範例2
private static void method() { }
-
-
注意事項
- 預設方法可以呼叫私有的靜態方法和非靜態方法
- 靜態方法只能呼叫私有的靜態方法
3.方法引用
3.1體驗方法引用【理解】
-
方法引用的出現原因
在使用Lambda表示式的時候,我們實際上傳遞進去的程式碼就是一種解決方案:拿引數做操作
那麼考慮一種情況:如果我們在Lambda中所指定的操作方案,已經有地方存在相同方案,那是否還有必要再寫重複邏輯呢?答案肯定是沒有必要
那我們又是如何使用已經存在的方案的呢?
這就是我們要講解的方法引用,我們是通過方法引用來使用已經存在的方案
-
程式碼演示
public interface Printable { void printString(String s); } public class PrintableDemo { public static void main(String[] args) { //在主方法中呼叫usePrintable方法 // usePrintable((String s) -> { // System.out.println(s); // }); //Lambda簡化寫法 usePrintable(s -> System.out.println(s)); //方法引用 usePrintable(System.out::println); } private static void usePrintable(Printable p) { p.printString("愛生活愛Java"); } }
3.2方法引用符【理解】
-
方法引用符
:: 該符號為引用運算子,而它所在的表示式被稱為方法引用
-
推導與省略
- 如果使用Lambda,那麼根據“可推導就是可省略”的原則,無需指定引數型別,也無需指定的過載形式,它們都將被自動推導
- 如果使用方法引用,也是同樣可以根據上下文進行推導
- 方法引用是Lambda的孿生兄弟
3.3引用類方法【應用】
引用類方法,其實就是引用類的靜態方法
-
格式
類名::靜態方法
-
範例
Integer::parseInt
Integer類的方法:public static int parseInt(String s) 將此String轉換為int型別資料
-
練習描述
-
定義一個介面(Converter),裡面定義一個抽象方法 int convert(String s);
-
定義一個測試類(ConverterDemo),在測試類中提供兩個方法
-
一個方法是:useConverter(Converter c)
-
一個方法是主方法,在主方法中呼叫useConverter方法
-
-
-
程式碼演示
public interface Converter { int convert(String s); } public class ConverterDemo { public static void main(String[] args) { //Lambda寫法 useConverter(s -> Integer.parseInt(s)); //引用類方法 useConverter(Integer::parseInt); } private static void useConverter(Converter c) { int number = c.convert("666"); System.out.println(number); } }
-
使用說明
Lambda表示式被類方法替代的時候,它的形式引數全部傳遞給靜態方法作為引數
3.4引用物件的例項方法【應用】
引用物件的例項方法,其實就引用類中的成員方法
-
格式
物件::成員方法
-
範例
“HelloWorld”::toUpperCase
String類中的方法:public String toUpperCase() 將此String所有字元轉換為大寫
-
練習描述
-
定義一個類(PrintString),裡面定義一個方法
public void printUpper(String s):把字串引數變成大寫的資料,然後在控制檯輸出
-
定義一個介面(Printer),裡面定義一個抽象方法
void printUpperCase(String s)
-
定義一個測試類(PrinterDemo),在測試類中提供兩個方法
- 一個方法是:usePrinter(Printer p)
- 一個方法是主方法,在主方法中呼叫usePrinter方法
-
-
程式碼演示
public class PrintString { //把字串引數變成大寫的資料,然後在控制檯輸出 public void printUpper(String s) { String result = s.toUpperCase(); System.out.println(result); } } public interface Printer { void printUpperCase(String s); } public class PrinterDemo { public static void main(String[] args) { //Lambda簡化寫法 usePrinter(s -> System.out.println(s.toUpperCase())); //引用物件的例項方法 PrintString ps = new PrintString(); usePrinter(ps::printUpper); } private static void usePrinter(Printer p) { p.printUpperCase("HelloWorld"); } }
-
使用說明
Lambda表示式被物件的例項方法替代的時候,它的形式引數全部傳遞給該方法作為引數
3.5引用類的例項方法【應用】
引用類的例項方法,其實就是引用類中的成員方法
-
格式
類名::成員方法
-
範例
String::substring
public String substring(int beginIndex,int endIndex)
從beginIndex開始到endIndex結束,擷取字串。返回一個子串,子串的長度為endIndex-beginIndex
-
練習描述
-
定義一個介面(MyString),裡面定義一個抽象方法:
String mySubString(String s,int x,int y);
-
定義一個測試類(MyStringDemo),在測試類中提供兩個方法
-
一個方法是:useMyString(MyString my)
-
一個方法是主方法,在主方法中呼叫useMyString方法
-
-
-
程式碼演示
public interface MyString { String mySubString(String s,int x,int y); } public class MyStringDemo { public static void main(String[] args) { //Lambda簡化寫法 useMyString((s,x,y) -> s.substring(x,y)); //引用類的例項方法 useMyString(String::substring); } private static void useMyString(MyString my) { String s = my.mySubString("HelloWorld", 2, 5); System.out.println(s); } }
-
使用說明
Lambda表示式被類的例項方法替代的時候
第一個引數作為呼叫者
後面的引數全部傳遞給該方法作為引數
3.6引用構造器【應用】
引用構造器,其實就是引用構造方法
-
l格式
類名::new
-
範例
Student::new
-
練習描述
-
定義一個類(Student),裡面有兩個成員變數(name,age)
並提供無參構造方法和帶參構造方法,以及成員變數對應的get和set方法
-
定義一個介面(StudentBuilder),裡面定義一個抽象方法
Student build(String name,int age);
-
定義一個測試類(StudentDemo),在測試類中提供兩個方法
-
一個方法是:useStudentBuilder(StudentBuilder s)
-
一個方法是主方法,在主方法中呼叫useStudentBuilder方法
-
-
-
程式碼演示
public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public interface StudentBuilder { Student build(String name,int age); } public class StudentDemo { public static void main(String[] args) { //Lambda簡化寫法 useStudentBuilder((name,age) -> new Student(name,age)); //引用構造器 useStudentBuilder(Student::new); } private static void useStudentBuilder(StudentBuilder sb) { Student s = sb.build("林青霞", 30); System.out.println(s.getName() + "," + s.getAge()); } }
-
使用說明
Lambda表示式被構造器替代的時候,它的形式引數全部傳遞給構造器作為引數
相關文章
- 零基礎學Java-基礎語法篇day1Java
- Java-基礎語法19:網路程式設計Java程式設計
- Java-基礎-反射Java反射
- Java-基礎-HashMapJavaHashMap
- Java-基礎-ArrayListJava
- Java基礎-語法基礎Java
- 基礎語法
- 英語語法基礎
- Java-基礎-LinkedListJava
- java-基礎-泛型Java泛型
- scala基礎語法-----Spark基礎Spark
- Dart語法基礎Dart
- Vue基礎語法Vue
- Java 基礎語法Java
- CSS 基礎語法CSS
- jQuery基礎語法jQuery
- Scala基礎語法
- redis 基礎語法Redis
- mysql基礎語法MySql
- jQuery 基礎語法jQuery
- Markdown 基礎語法
- JavaScript 基礎語法JavaScript
- JAVA語法基礎Java
- markdow基礎語法
- CSS基礎語法CSS
- go 基礎語法Go
- Markdown基礎語法
- JavaScript 基礎卷(一):基礎語法JavaScript
- Python基礎:語法基礎(3)Python
- 【Java基礎】--深入剖析基礎語法Java
- Dart語法篇之基礎語法(一)Dart
- Golang 基礎之基礎語法梳理 (三)Golang
- Drools之基礎語法
- kotlin基礎語法Kotlin
- C++基礎語法C++
- JAVA基礎語法(一)Java
- Dart的基礎語法Dart
- Python 基礎語法Python