了解lambda之前先了解下什么是函數式接口,函數式接口即接口里必須有一個抽象方法(抽象的方法只能有一個,可以有其他的用default修飾的方法以及從Object繼承的方法)
jdk8里新增了一個@FunctionalInterface注解,這個注解標注此接口為函數式接口,但是並不是必須的,任何滿足我上面所說的只有一個抽象方法的接口都可以稱之為函數式接口,但是如果一個接口上標注了此注解,就必須滿足上述條件
lambda表達式用來重寫函數式接口中的那個抽象方法,lambda直接看做匿名抽象類,因為lambda可以對接口賦值
lambda表達式的語法包括3個部分:
1.參數列表(...) 如(String s,Integer i) () (s) 等,沒有參數時就是(),只有一個參數時可以寫成str,省略掉參數的小括號
2.箭頭 ->
3.執行的代碼 { },執行的代碼只有一行時,可以省略大括號
4.需要注意的是lambda無法在其方法體中修改局部變量的值
lambda表達式整體看作一個某個接口的匿名類,lambda的參數,方法體是該匿名類的下唯一重寫抽象方法的參數,方法體,lambda是對匿名類的簡化
下面以創建線程為例
1 //匿名內部類創建線程
2 new Thread(new Runnable() { 3 @Override 4 public void run() { 5 System.out.println("匿名內部類啟動線程"); 6 } 7 }).start(); 8
9 //使用lambda表達式啟動一個新的線程 10 //()對應run方法的參數 11 //->后面表示run的方法體
12 new Thread(()->System.out.println("使用lambda啟動線程")).start();
來看下jedis中execute方法關於lambda的例子
從上圖可以看到execute方法需要一個RedisCallBack,這是一個接口,內部只有一個抽象方法,雖然沒有@FunctionalInterface注解,但這是一個抽象接口
唯一的抽象方法doInRedis需要一個RedisConnection參數,返回一個泛型參數,我們抽取下excute需要的關於語法的關鍵代碼
1 execute((RedisCallback<List<Object>>) connection -> { 2 connection.openPipeline(); 3 return xx; 4 });
connection -> {connection.openPipeline();return xx;}); connection是doInRedis的形參,{}中doInRedis的方法體,而connection前面的(RedisCallback<List<Object>>)是對lambda的類型說明(RedisCallback<T>)
下面再舉一個Runnable接口的例子
1 /**
2 * lambda語法包括3個部分: 3 * (參數列表)->{方法體;} 4 * 只有一個參數時,()可以省略 5 * 方法體只有一行時可以省略{;} 6 * @author tele 7 * 8 */
9 public class Demo1 { 10 public static void main(String[] args) { 11 List<Integer> list = new ArrayList<Integer>(); 12 list.add(1); 13 list.add(2); 14 list.add(3); 15 //遍歷list
16 list.forEach(i->System.out.println(i)); 17
18
19 //>=可以直接判斷符號
20 /* int a = 1; 21 int b = 2; 22 System.out.println(b>=a?"b>a":"b<a");*/
23
24 //匿名內部類創建線程
25 new Thread(new Runnable() { 26 @Override 27 public void run() { 28 System.out.println("匿名內部類啟動線程"); 29 } 30 }).start(); 31
32 //使用lambda表達式啟動一個新的線程 33 //()對應run方法的參數 34 //->后面表示run的方法體
35 new Thread(()->System.out.println("使用lambda啟動線程")).start(); 36
37
38 //如果要使用lambda來聲明接口那么接口中只能有一個抽象方法 39 //因為函數接口是只有一個抽象方法的接口(抽象的方法只能有一個,可以有其他的用default修飾的方法)
40
41 String s = "lambda test"; 42 int i= 100; 43 MyInterface myInterface = (str,m)->{ 44 //i++; 錯誤,無法對i的值進行修改
45 System.out.println(i); 46 System.out.println(str + " " + m); 47 return str+"----"+str; 48 }; 49 String result = myInterface.test(s,0); 50 System.out.println(result); 51
52
53 } 54
55 //定義一個內部的函數式接口
56 static interface MyInterface { 57 //void test(String s,int i);
58 String test(String s,int i); 59 } 60 }
到這再次說明,lambda表達式是重寫了接口中的抽象方法,包括第16行的代碼把lambda表達式傳入到foreach中,傳入的lambda表達式實質是對Consumer接口的accept方法的重寫
參數類型的省略是因為java的類型推斷,編譯器知道函數式接口中的那個抽象方法需要什么類型
下面結合Predicate接口再來深入了解下lambda表達式,這個接口主要用於斷言,當然他是一個函數式接口,可以看到他的抽象方法是test(),所以我們寫的lambda表達式就是重寫test方法
注意這里用了泛型
先看filter方法,filter方法對list進行遍歷,滿足test()后進行輸出,而test的方法體就是我們傳入的lambda表達式,從這一點上看,使用lambda有點繞的地方就是按照以往的做法我們調用filter時出了傳入list,另一個參數應該為Precidate類型,然而使用了lambda后,我們直接傳入Predicate接口中的抽象方法的參數與方法體即可,即使我們傳入一個Predicate類型的參數,接下來仍然是去調用test(),從這點看lambda可以說是一步到位了
完整代碼,and對應&& or對應|| negate對應!
1 /**
2 * Predicate接口的使用 3 * @author tele 4 * 5 */
6 public class Demo2 { 7 public static void main(String[] args) { 8 List<String> list = Arrays.asList("java","hadoop","python","php","lucene"); 9 filter(list,s->s.startsWith("j"));//java 10 // filter(list, s->true);//全部輸出
11
12
13 Predicate<String> condition1 = str->str.startsWith("j"); 14 Predicate<String> condition2 = str->str.endsWith("h"); 15
16 //and
17 Predicate<String> andCondition = condition1.and(condition2); 18 boolean result = andCondition.test("jsadh"); 19 System.out.println(result);//true 20
21 //or
22 Predicate<String> orCondition = condition1.or(condition2); 23 result = orCondition.test("jasd"); 24 System.out.println(result);//true 25
26 //negate,對判斷條件取反
27 Predicate<String> negate = condition1.negate(); 28 System.out.println(negate.test("aj"));//true 29
30 //isEqual(了解,比較兩個對象是否相等)
31 result = Predicate.isEqual("as").test("aaa"); 32 System.out.println(result); 33
34 } 35
36 //test方法是predicate中的唯一一個抽象方法
37 public static void filter(List<String> list,Predicate<String> predicate) { 38 list.forEach(t->{ 39 if(predicate.test(t)){ 40 System.out.println(t); 41 } 42 }); 43 } 44 }