好程式設計師Java教程分享Java8.0新特性之Lambda表示式

好程式設計師IT發表於2019-10-30

  好程式設計師Java 教程分享 Java8.0 新特性之 Lambda 表示式: Java 8  已經發布很久了,很多報導表明 Java 8  是一次重大的版本升級。本篇文章,主要給大家介紹的是 lambda 表示式。

Lambda 表示式

Lambda 表示式(也稱為閉包)是 Java 8 中最大和最令人期待的語言改變。它允許我們將函式當成引數傳遞給某個方法,或者把程式碼本身當作資料處理:函式式開發者非常熟悉這些概念。

很多JVM 平臺上的語言( Groovy Scala 等)從誕生之日就支援 Lambda 表示式,但是 Java 開發者沒有選擇,只能使用匿名內部類代替 Lambda 表示式。

Lambda 的設計耗費了很多時間和很大的社群力量,最終找到一種折中的實現方案,可以實現簡潔而緊湊的語言結構。而 lambda 表示式的使用需要和函式式介面結合。

1. 函式式介面

1.1. 概念

函式式介面在Java 中是指:有且僅有一個抽象方法的介面。 函式式介面,即適用於函數語言程式設計場景的介面。而 Java 中的函數語言程式設計體現就是 Lambda ,所以函式式介面就是可 以適用於 Lambda 使用的介面。只有確保介面中有且僅有一個抽象方法, Java 中的 Lambda 才能順利地進行推導。 備註:“語法糖”是指使用更加方便,但是原理不變的程式碼語法。例如在遍歷集合時使用的 for-each 語法,其實 底層的實現原理仍然是迭代器,這便是“語法糖”。從應用層面來講, Java 中的 Lambda 可以被當做是匿名內部 類的“語法糖”,但是二者在原理上是不同的。

1.2, 格式

只要確保介面中有且僅有一個抽象方法即可:

1.  修飾符  interface  介面名稱  {           

2.     public abstract  返回值型別 方法名稱 ( 可選引數資訊 );  

3. }  

1.3 @FunctionalInterface 註解

 @Override  註解的作用類似, Java 8 中專門為函式式介面引入了一個新的註解:  @FunctionalInterface  。該註解可用於一個介面的定義上:

1. @FunctionalInterface  

2. public interface MyFunctionalInterface {  

3.     void myMethod();  

4. }

一旦使用該註解來定義介面,編譯器將會強制檢查該介面是否確實有且僅有一個抽象方法,否則將會報錯。需要注  意的是,即使不使用該註解,只要滿足函式式介面的定義,這仍然是一個函式式介面,使用起來都一樣.

2. 函式式介面的使用

2.1 函式式介面作為引數 , 方法不帶引數

1. // 定義函式式介面  

2. public interface MyInterface{  

3.      

4.     public abstract void show();  

5.      

6. }  

7.   

8. // 使用 ( 匿名內部類物件 / 函式式 )   

9. public class Demo01 {  

10.   

11.     public static void main(String[] args) {  

12.         method01(new MyInterface01() {  

13.   

14.             @Override  

15.             public void show() {  

16.                 System.out.println(" 你好 , 函式式介面 ");  

17.             }  

18.         });  

19.         //  函式式  

20.         method01(() -> {  

21.             System.out.println(" 你好 , 函式式介面 ");  

22.         });  

23.         //  函式式簡寫 ( 如果方法體中只有一句程式碼 )  

24.         method01(() -> System.out.println(" 你好 , 函式式介面 "));  

25.     }  

26.   

27.     public static void method01(MyInterface01 inter) {  

28.         inter.show();  

29.     }  

30.   

31. }

函式式介面的優勢

函式式介面比匿名內部類物件產生更少的位元組碼物件, 提升 java 執行效率 .

2.2,  函式式介面作為引數 , 方法帶引數

1. // 定義函式式介面  

2.     public interface MyInterface02 {  

3.   

4.         public abstract void show(String msg1, String msg2);  

5.   

6.     }  

7.   

8.     // 使用函式式介面  

9.     public static void main(String[] args) {  

10.         // 匿名內部類物件  

11.         method01(new MyInterface02() {  

12.   

13.             @Override  

14.             public void show(String msg1, String msg2) {  

15.                 System.out.println(msg1 + msg2);  

16.             }  

17.         });  

18.         // 函式式完整  

19.         method01((String msg1, String msg2) -> {  

20.             System.out.println(msg1 + msg2);  

21.         });  

22.         // 函式式簡寫  

23.         method01((msg1, msg2) -> System.out.println(msg1 + msg2));  

24.   

25.     }  

26.   

27.     public static void method01(MyInterface02 inter) {  

28.         inter.show("hello", " 函式式 ");  

29.     }

2.3,  函式式介面作為返回值 , 方法不帶引數

1.    // 定義函式式介面  

2.    public interface MyInterface02 {  

3.   

4.     public abstract void show(String msg1, String msg2);  

5.   

6.    }  

7. public static void main(String[] args) {  

8.   

9.     getInter1().show(" 你好 ", " 函式式 ");  

10.     getInter2().show(" 你好 ", " 函式式 ");  

11.   

12. }  

13.   

14. //  函式式完整  

15. public static MyInterface02 getInter1() {  

16.   

17.     return (String msg1, String msg2) -> {  

18.         System.out.println(msg1 + msg2);  

19.     };  

20. }  

21.   

22. //  函式式簡寫  

23. public static MyInterface02 getInter2() {  

24.   

25.     return (msg1, msg2) -> System.out.println(msg1 + msg2);  

26. }  

3. 函數語言程式設計應用場景

3.1, 概念

在兼顧物件導向特性的基礎上,Java 語言透過 Lambda 表示式使用函式式介面 , 就叫做函數語言程式設計

3.2,  使用 lambada 作為引數

如果拋開實現原理不說,Java 中的 Lambda 表示式可以被當作是匿名內部類的替代品。如果方法的引數是一個函式 式介面型別,那麼就可以使用 Lambda 表示式進行替代。

1. public class Demo04Runnable{  

2.     private static void startThread(Runnable task){   

3.         new Thread(task).start();   

4.     }        

5.     public static void main(String[] args) {   

6.         startThread(() >System.out.println(" 執行緒執行 "));   

7.     }   

8. }  

3.3,  使用函式式介面作為返回值

如果一個方法的返回值型別是一個函式式介面,那麼就可以直接返回一個Lambda 表示式。

1. public class Demo06Comparator {  

2.   

3.     private static Comparator<Integer> getComparator(){  

4.         return (num1,num2) > num1 - num2;  

5.     }  

6.      

7.     public static void main(String[] args) {  

8.         Integer[] array = {3,2,1};   

9.         Arrays.sort(array, getComparator());   

10.         // 遍歷陣列  

11.     }   

12. }

3.4,  函式式介面的方法有返回值

1. public static void main(String[] args) {  

2.   

3.         showMsg(new MyInterface03() {  

4.   

5.             @Override  

6.             public String getMsg() {  

7.                 return "hello functional interface";  

8.             }  

9.         });  

10.   

11.         // lambada 表示式  

12.         showMsg(() -> {  

13.   

14.             return "hello1 functional interface";  

15.         });  

16.   

17.         // lambda 表示式簡寫  

18.         showMsg(() -> "hello1 functional interface");  

19.   

20.     }  

21.   

22.     public static void showMsg(MyInterface03 inter) {  

23.         String msg = inter.getMsg();  

24.         System.out.println(msg);  

25.     }

4. 常用函式式介面 (Supplier 介面 )

JDK 提供了大量常用的函式式介面以豐富 Lambda 的典型使用場景,它們主要在  java.util.function  包中被提供。 下面是簡單的幾個介面及使用示例。

4.1,Supplier 介面  

java.util.function.Supplier<T>  介面僅包含一個無參的方法:  T get()  。用來獲取一個泛型引數指定型別的物件資料。由於這是一個函式式介面,這也就意味著對應的 Lambda 表示式需要“對外提供”一個符合泛型型別的物件資料

4.2, 基本使用

1. private static String getString(Supplier<String> function ){  

2.     return function.get();  

3. }  

4. public static void main(String[] args){  

5.     String msgA="Hello";  

6.     String msgB="World";  

7.     System.out.println(getString(()->msgA+msgB));  

8. }  

4.2 ,綜合案例

  需求: 使用  Supplier  介面作為方法引數型別,透過 Lambda 表示式求出 int 陣列中的最大值。提示:介面的泛型請使用  java.lang.Integer  類。

1. public static void main(String[] args) {  

2.     Integer max = getMax(()->{  

3.         Integer[] nums = {1,2,3,4};  

4.         int max2 = nums[0];  

5.         for (Integer num : nums) {  

6.             if(max2 < num){  

7.                 max2 = num;  

8.             }  

9.         }  

10.         return max2;  

11.     });  

12.     System.out.println(max);  

13. }  

14.   

15. public static Integer getMax(Supplier<Integer> supplier){  

16.     return supplier.get();  

17. }  

  

5. 常用函式式介面 (Consumer 介面 )

5.1,Consumer 介面  

java.util.function.Consumer<T>  介面則正好與 Supplier 介面相反,它不是生產一個資料,而是消費一個資料, 其資料型別由泛型決定

5.2,accept 方法   

Consumer  介面中包含抽象方法  void accept(T t)  ,意為消費一個指定泛型的資料。基本使用如:

1. public static void main(String[] args) {  

2.     consumeString((msg)->System.out.println(msg));  

3. }  

4.   

5.   

6. public static void consumeString(Consumer<String> consumer){  

7.      consumer.accept("hello");  

8. }  

5.3, andThen 方法   

如果一個方法的引數和返回值全都是 Consumer  型別,那麼就可以實現效果:消費資料的時候,首先做一個操作, 然後再做一個操作,實現組合。而這個方法就是  Consumer  介面中的 default 方法  andThen

1. default Consumer<T> andThen(Consumer<? super T> after) {  

2.     Objects.requireNonNull(after);  

3.     return (T t) -> { accept(t); after.accept(t); };  

4. }  

: java.util.Objects  的  requireNonNull  靜態方法將會在引數為 null 時主動丟擲  NullPointerException  異常。這省去了重複編寫 if 語句和丟擲空指標異常的麻煩。

需求:先列印大寫HELLO, 再列印小寫 hello

1. public static void main(String[] args) {  

2.     consumeString((msg) -> System.out.println(msg.toUpperCase()),   

3.             (msg) -> System.out.println(msg.toLowerCase()));  

4. }  

5.   

6. public static void consumeString(Consumer<String> consumer1, Consumer<String> consumer2) {  

7.     consumer1.andThen(consumer2).accept("hello");  

8. }  

6. 常用函式式介面 (Predicate 介面 )

有時候我們需要對某種型別的資料進行判斷,從而得到一個boolean 值結果。這時可以使用  java.util.function.Predicate<T>  介面

6.1, test 方法  

Predicate  介面中包含一個抽象方法:  boolean test(T t)  。用於條件判斷的場景

1. public enum SingleClass06 {  

2.     INSTANCE;  

3. }

6.2 ,基本使用

1. public static void main(String[] args) {  

2.     System.out.println(predicateTest((msg) -> msg.length() > 3, "hello"));  

3. }  

4.   

5.   

6. public static boolean predicateTest(Predicate<String> predicate,String msg){  

7.     return predicate.test(msg);  

8.      

9. }

7. 總結

在本文中, 我們學會了使用 lambda 表示式的不同方式 , 同時也學習了 java8.0 開始自帶的一些常用函式式介面。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2661911/,如需轉載,請註明出處,否則將追究法律責任。

相關文章