java8實戰二------lambda表達式和函數式接口,簡單就好


一、Lambda

可以把Lambda表達式理解為簡潔地i表示可傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還是一個可以拋出的異常列表。

聽上去,跟我們用的匿名類,匿名方法什么的很像。我們繼續看看把。

第一篇,我們做的事分蘋果,這次我們給蘋果根據重量來做個Comparator吧。

先來以前的:

1  Comparator<Apple> byWeight=new Comparator<Apple> () {
2             @Override
3             public int compare(Apple o1, Apple o2) {
4                 return o1.getWeight ().compareTo (o2.getWeight ());
5             }
6         };

用了lambda:

1  Comparator<Apple> byWeight=(Apple a1,Apple a2)->a1.getWeight ().compareTo (a2.getWeight ());

是不是很簡單。簡單講一下lambda的格式,由lambda參數、箭頭、lambda主體三部分組成;

其中lambda參數也可以不用寫類型,它會根據上下文自己判斷類型,后面有例子出現。

而lambda主題如果像以上表達式只有一句的話,可以不叫{},但有多條語句的話必須加{}。

二、函數式接口

1 public interface Pridicate<T>{
2        boolean test(T t);
3 }

類似上面的接口一樣,只定義一個方法的接口,我們稱之為函數式接口。Runable,Comparator都是一個函數式接口。當然,並不是嚴格意義上的只有一個方法,還可以有default修飾的默認方法。

函數式接口的抽象方法的簽名基本上就是Lambda表達式的簽名,稱之為函數描述符。比如,Runable的run()方法,什么也不接收,什么也不返回,Runable可以作為run方法的簽名。函數描述符為()->void 。給個栗子!

 1 public class Demo6 {
 2     public static void main(String[] args) {
 3         //old
 4        process (new Runnable () {
 5            @Override
 6            public void run() {
 7                System.out.println ("This is old");
 8            }
 9        });
10        //new
11         process (()-> System.out.println ("This is new "));
12     }
13     public static void process(Runnable r){
14         r.run ();
15     }
16 }

我們知道process()方法接收的是一個函數式接口,所以我們直接可以用lambda表達式來表示這個函數式接口,()表示不接受參數,lambda主體不返回參數,

完成的功能和上面匿名是一樣的。我再來個反例!

1 Predicate<Apple> predicate=(Apple a)->a.getWeight ();
2 //Bad return type in lambda expression: Integer cannot be converted to boolean

Apple的getWeight是個Integer返回類型,而,我們需要的是一個boolean類型,所以報錯。這里解釋一下Predicate等類。

(1)Predicate<T>定義了一個抽象方法test(),返回boolean值。后面可以用來做filter的條件。

         像上面的反例,加入我在Apple加一個方法

1  public boolean islight(){
2         if(this.getWeight ()>4){
3             return false;
4         }
5         return true;
6     }

我們就可以寫  Predicate<Apple> predicate=(Apple a)->a.islight (); 這樣就不會報錯。

java8中常用的函數式接口:

所謂原始類型轉化,其實很容易理解,像IntToDoubleFunction: IntToDoubleFunction i=(int s)->s*1.0; 對傳入的s返回double。不用聲明泛型,根據字面意思

int轉double。

此外,lambda其實能根據上下文推斷傳入參數的類型: IntToDoubleFunction i=s->s*1.0; 因為IntToDoubleFunction的函數描述符式T->R,它自動判斷s是int。

三、方法引用

上文中我們設計了一個Predicate<Apple>來區分輕重的蘋果,我們先來看看方法引用。

1         Predicate<Apple> predicate=(Apple a)->a.islight ();
2         //方法引用
3         Predicate<Apple> predicate1=Apple::islight;

我們看看,Apple的islight()方法是傳入一個Apple,返回一個boolean。函數描述符為Apple->boolean。我們先寫個自己的Predicate。

1 class MyPredicate implements Predicate<Apple>{
2     @Override
3     public boolean test(Apple apple) {
4         if (apple.islight ()){
5             return true;
6         }
7         return false;
8     }
9 }

使用函數式接口的進階順序是:(1)自己寫實現類,(2) Predicate<Apple> predicate=a->a.islight (); 

                                                    (3) Predicate<Apple> predicate1=Apple::islight;  

(2)和(3)都是直接用lambda表達式表示Predicate。而(3)中用方法引用,使得代碼,更加簡潔。

我們應該注意:我們調的方法是Apple的islight(),函數描述符要符合函數式接口的函數描述符。合理的使用能使你的代碼更加簡潔。

這次,就寫這些了。

陸續更新。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM