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(),函式描述符要符合函式式介面的函式描述符。合理的使用能使你的程式碼更加簡潔。
這次,就寫這些了。
陸續更新。