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