簡單易懂的java8新特性之lambda表達式知識總結
一、概念
從本質上來說,它就是一個匿名函數,可以用來直接實現接口中的方法,從而簡化代碼。但是Lambda有一個限制,不能實現接口中的所有方法,所以Lambda表達式隻能用於有且僅有一個必須需要實現的方法接口,這裡需要註意必須需要實現這六個字。
public interface Printer { //有一個需要實現的方法,可以使用Lambda表達式 void print(); }
public interface Printer { //有一個需要實現的方法,可以使用Lambda表達式 void print(); //這裡雖然有一個方法,但接口提供瞭默認實現,因此不是必須要實現的 default void printDetail(){} }
public interface Printer { //有一個需要實現的方法,可以使用Lambda表達式 void print(); //這裡雖然有一個需要實現的方法,但不是必須要實現的,因為toString()是Object類中的. String toString(); }
public interface Printer { //有一個需要實現的方法,可以使用Lambda表達式 void print(); //這裡雖然有一個需要實現的方法,但不是必須要實現的,因為toString()是Object類中的. String toString(); }
像這種隻有一個必須要實現的方法的接口,在java8中稱之為函數式接口,在定義接口時可以在接口名上方加上@FunctionInterface
標簽,用於驗證此接口是否為函數式接口。如果這個接口定義好之後不是函數式接口,那麼接口名處會報錯。
在使用Lambda表達式的時候,不需要關註方法名,隻需要關註方法參數和返回值即可。基本語法很簡單:
(參數列表)->{ 方法體 };
二、用法比較
java中實現接口的方式在java8之前有兩種:定義接口的實現類,使用匿名類,但Lambda表達式相比於這種方法都簡單很多。以上文的Printer接口為例,實現如下:
2.1 實現類
class PrinterImpl implements Printer{ @Override public void print() { System.out.println("Hello World"); } }
2.2 匿名類
class PrinterAnonymous { Printer printer = new Printer() { @Override public void print() { System.out.println("Hello World"); } }; }
2.3 Lambda
class PrinterLambda{ Printer p = ()-> System.out.println("Hello World"); }
比較上文三種實現方式,很顯示Lambda的實現比前兩種簡單很多。
三、基本用法
3.1 無參數無返回值接口方法
@FunctionalInterface public interface Printer { void print(); } public class Tester { public static void main(String[] args) { // 方法一,無返回值的情況,方法體隻有一條語句,可以省略大括號 Printer p1 = () -> System.out.println("Hello World 1"); p1.print(); // 方法二,標準定義 Printer p2 = () -> { System.out.println("Hello World 2"); }; p2.print(); } }
3.2 一個參數無返回值接口方法
@FunctionalInterface public interface Printer { void print(String str); } public class Tester { public static void main(String[] args) { // 方法一,無返回值的情況,方法體隻有一條語句,可以省略大括號 //因為這裡隻有一個參數,小括號也可以省略,小括號省略的前提是:有且僅有一個參數 //Printer p1 = s -> System.out.println(s); Printer p1 = (s) -> System.out.println(s); p1.print("Hello World 1"); // 方法二,無返回值的情況,方法體隻有一條語句,可以省略大括號 Printer p2 = (String s) -> System.out.println(s); p2.print("Hello World 2"); // 方法三,標準定義 Printer p3 = (String s) -> { System.out.println(s); }; p3.print("Hello World 3"); } }
3.3 多個參數無返回值接口方法
@FunctionalInterface public interface Printer { void print(String str1,String str2); } public class Tester { public static void main(String[] args) { // 方法一,無返回值的情況,方法體隻有一條語句,可以省略大括號 //參 Printer p1 = (s1,s2) -> System.out.println(s1+" "+s2); p1.print("Hello World 1","Java 1"); // 方法二,無返回值的情況,方法體隻有一條語句,可以省略大括號 Printer p2 = (String s1,String s2) -> System.out.println(s1+" "+s2); p2.print("Hello World 2","Java 2"); // 方法三,標準定義 Printer p3 = (String s1,String s2) -> { System.out.println(s1+" "+s2); }; p3.print("Hello World 3","Java 3"); } }
3.4 無參數有返回值接口方法
@FunctionalInterface public interface Printer { boolean print(); } public class Tester { public static void main(String[] args) { // 方法一,有返回值的情況,隻有一條語句,return關鍵字的有無決定能否活力大括號 Printer p1 = () -> true; boolean has1 = p1.print(); System.out.println(has1);//測試返回結果 // 方法二,標準定義 Printer p2 = () -> {return true;}; boolean has2 = p2.print(); System.out.println(has2);//測試返回結果 } }
3.5 一個參數有返回值接口方法
@FunctionalInterface public interface Printer { boolean print(boolean good); } public class Tester { public static void main(String[] args) { // 方法一,有返回值的情況,隻有一條語句,return關鍵字的有無決定能否活力大括號 //因為這裡隻有一個參數,小括號也可以省略,小括號省略的前提是:有且僅有一個參數 //Printer p1 = good -> good; Printer p1 = (good) -> good; boolean has1 = p1.print(true); System.out.println(has1); // 方法二,標準定義 Printer p2 = (good) -> {return good;}; boolean has2 = p2.print(false); System.out.println(has2); } }
3.6 多個參數有返回值接口方法
@FunctionalInterface public interface Printer { boolean print(boolean good1,boolean good2); } public class Tester { public static void main(String[] args) { // 方法一,有返回值的情況,隻有一條語句,return關鍵字的有無決定能否活力大括號 Printer p1 = (good1,good2) -> good1; boolean has1 = p1.print(true,false); System.out.println(has1); // 方法二,標準定義 Printer p2 = (good1,good2) -> {return good1;}; boolean has2 = p2.print(false,false); System.out.println(has2); } }
四、函數引用
在實現一個接口的方法時,如果現有的其他地方的某個函數已經實現瞭接口方法的邏輯,可以使用方法引用直接將這個邏輯引用過來。
4.1 靜態方法引用
語法:
接口名 變量名 = 類 ::已實現的方法
註意事項:
- 在引用的方法後面,不要添加小括號
- 引用的這個方法,參數和返回值,必須要跟接口中定義的一致
示例:
Printer 需要實現的方法在Checker中有同樣的實現,這樣就可以直接引用過來
@FunctionalInterface public interface Printer { String print(boolean good1,boolean good2); } public class Checker { public static String check(boolean a,boolean b) { if(a && b) { return "Java is good"; }else if (!a && b) { return "Java is better"; } return "Java is best"; } } public class Tester { public static void main(String[] args) { Printer p1 = Checker::check;//用類名來引用 System.out.println(p1.print(true, true)); } }
4.2 非靜態方法引用
語法:
接口名 變量名 = 對象 ::靜態方法
註意事項:
- 在引用的方法後面,不要添加小括號
- 引用的這個方法,參數和返回值,必須要跟接口中定義的一致
示例:
Printer 需要實現的方法在Checker中有同樣的實現,這樣就可以直接引用過來
@FunctionalInterface public interface Printer { String print(boolean good1,boolean good2); } public class Checker { public String check(boolean a,boolean b) { if(a && b) { return "Java is good"; }else if (!a && b) { return "Java is better"; } return "Java is best"; } } public class Tester { public static void main(String[] args) { Printer p1 = new Checker()::check;//必須用對象來引用 System.out.println(p1.print(true, true)); } }
4.3 構造方法的引用
如果一個函數式接口中定義的方法僅僅是為瞭得到一個對象,此時我們就可以使用構造方法的引用,簡化這個方法的實現
語法:
接口名 變量名 = 類名 ::new
註意事項:
可以通過接口中的方法參數,區分引用不同的構造方法
示例:
@FunctionalInterface public interface Printer1 { Checker getCheck(); } @FunctionalInterface public interface Printer2 { Checker getCheck(int a); } public class Checker { int times; public Checker() { System.out.println("I am none parameter"); } public Checker(int a) { System.out.println("I have one parameter"); } } public class Tester { public static void main(String[] args) { //引用無參構造方法 Printer1 p1 = Checker::new; p1.getCheck(); //引用有參構造方法 Printer2 p2 = Checker::new; p2.getCheck(1); } }
4.4 對象方法的特殊引用
如果實現某些接口的時候,Lambda表達式中包含瞭某一個對象,此時方法體中,直接使用這個對象調用它的某一個方法就可以完成整個的邏輯。其他的參數,可以作為調用方法的參數。此時,可以對這種實現進行簡化。
示例:
@FunctionalInterface public interface Printer1 { int getCheck(Checker checker); } @FunctionalInterface public interface Printer2 { void setCheck(Checker checker, int a); } public class Tester { public static void main(String[] args) { Checker checker = new Checker(); checker.setTimes(100); // 沒有簡化前,按照之前的方法使用lambda表達式 Printer1 p1 = x -> x.getTimes(); System.out.println(p1.getCheck(checker));//測試 // 簡化之後 Printer1 p11 = Checker::getTimes; System.out.println(p11.getCheck(checker));//測試 // 沒有簡化前,按照之前的方法使用lambda表達式 Printer2 p2 = (x,y)-> x.setTimes(y); p2.setCheck(checker, 50); System.out.println(checker.getTimes());//測試 // 簡化之後 Printer2 p22 = Checker::setTimes; p22.setCheck(checker, 30); System.out.println(checker.getTimes());//測試 } }
五、註意
當在Lambda表達式中使用瞭某一個局部變量,那麼這個局部變量的值在Lambda表達式之外,不可以被改變,因為默認將其定義成final常量。但全局變量變量沒有這方面的限制。
示例:
@FunctionalInterface public interface Printer { void setTime(); } public class Tester { public static void main(String[] args) { int time = 10; Printer p = () -> System.out.println(time);//這裡出錯瞭,因為下一行對time進行修改 time = 15;//這裡的值不能改變,會導致上一行出錯 } }
基本概括瞭Lambda表達式的所有用法,不足之處,請諒解,謝謝!
到此這篇關於簡單易懂的java8新特性之lambda表達式知識總結的文章就介紹到這瞭,更多相關java lambda表達式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java方法引用原理實例解析
- Java8語法糖之Lambda表達式的深入講解
- 關於JavaEE匿名內部類和Lambda表達式的註意事項
- java Lambda表達式的使用心得
- Java中Lambda表達式的使用詳細教程