1. 程式人生 > >java8實戰二------lambda表示式和函式式介面,簡單就好

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(),函式描述符要符合函式式介面的函式描述符。合理的使用能使你的程式碼更加簡潔。

這次,就寫這些了。

陸續更新。