什麼是 Lambda 表達式?java
爲何使用 Lambda ?算法
簡潔實現接口對接;閉包
雖然可使用 Lambda 表達式對某些接口進行實現,可是並非全部的接口均可以使用 Lambda 來實現;ide
實現要求:要實現的抽象方法只能是一個;函數
在 Java 8 中對接口實現了一個新特性
default
,被此方法修飾的方法在類中有一個默認實現,因此不影響使用 Lambda 的實現;優化
@FunctionalInterface:this
一個用來修飾函數式接口的,接口中的抽象方法只能有一個;.net
// 錯誤代碼展現 @FunctionalInterface interface Comparer{ int compare(int a,int b);// 方法一 int show(int a,int b); // 方法二 }
↑ ↑ ↑ 錯誤代碼展現 ↑ ↑ ↑線程
什麼是函數式接口?code
代碼示例
public class DEMO{ public static void main(String[] args){ // 方法一:使用接口實現類 Comparator comparator = new MyComparator(); //方法二:使用匿名內部類 Comparator comparator = new Comparator(){ @Override public int compare(int a,int b){ return a-b; } } //方法三:使用Lambda表達式 Comparator comparator2 = (a,b) -> a-b; } } // 一個接口 interface Comparator{ int compare(int a,int b); } //方法一:使用實現類實現接口 class MyComparator implements Comparator{ @Override public int compare(int a,int b){ return a-b; } }
基礎語法:
元素:
()
:用來描述參數列表{}
:用來描述方法體->
:分隔 Lambda 運算法,讀做:goes to
幾種狀況:
一、無參 無返回
// 無參 無返回 LambdaTest lam1 = ()->{ Sout("Hello World!"); } lam1.test(); // 結果:輸出`Hello World!`二、單個參 無返回
// 無參 單個返回值 LambdaTest lam2 = (int a)->{ Sout(a); } lam2.test(10); // 結果:輸出`10`三、多個參 無返回
LambdaTest lam3 = (int a,int b)->{ Sout(a+b); } lam3.test(10,11); // 結果:輸出`21`四、無參 有返回
LambdaTest lam4 = ()->{ Sout(100); return 100; } int ret = lam4.test(); // 結果:輸出`100` ; 返回 `100`五、有參數 有返回
LambdaTest lam5 = (int a)->{ Sout(a*2); return a*2; } int ret = lam5.test(10); // 結果:輸出`20` ; 返回 `20`
↑ ↑ ↑ 要注意 必定要定義相應的 函數式接口
↑ ↑ ↑
interface Lamx{ int test(int a,int b); } Lamx lamx = (int a,int b)->{ Sout("a=" + a + "\nb=" + b); // return a+b; }
上面報錯了?Lambda表達式如何知道有返回值?
Lambda 由於定義的接口有了說明,好比接口中寫
int test(int a);
第一個int
表示返回值類型,第二個int
表示參數類型,因此 捨去了return
就會報錯;
既然在定義接口的時候已經定義了類型,那麼是否是能夠在寫入參數的時候,將參數的類型描述給省略掉呢?
精簡1:省略參數描述int
代碼演示:
interface Lamx{ int test(int a,int b); } Lamx lamx = (a,b)->{ Sout("a=" + a + "\nb=" + b); return a+b; }
接口中已經說明了有int
類型的返回值,因此不寫return
是錯誤的;
兩個必須同時省略,不能一個寫一個不寫;
精簡2:省略小括號()
代碼演示:
interface Lamx{ int test(int a); } Lamx lamx = a -> { Sout("a=" + a ); return a; }
當 入參 只有一個的時候,能夠省略入參的 括號;
{}
interface Lamx{ int test(int a); } Lamx lamx = a -> Sout( a );
當 函數 只有一行的時候,能夠省略大括號;
return
interface Lamx{ int test(int a); } Lamx lamx = a -> a;
若是惟一一條語句是return
語句,那麼省略大括號的同時,也必須省略return
;
Lamx lamx = (a,b)->a+b; lamx.test(5,10);
public class Test{ public static void main(String[] args){ // 實現方式一: 傳統 Lambda 語法 Lamx lamx = a -> change(a); // 實現方式二: 雙" : "語法 Lamx lamx = Test::change; } public static int change(int a){ return a*2; } }
將 Lambda 指向一個已經實現的方法;語法規則 -- 方法隸屬者::方法名
此處的change
是一個靜態方法,隸屬者就是Test
類,因此就是Test::change
// 構造方法 public class Person{ public String name; public int age; public Person(){ Sout("Person類的 無參 構造方法執行了;"); } public Person(String name,int age){ this.name = name; this.age = age; Sout("Person類的 有參 構造方法執行了;"); } }
// Lambda 語法 public class Lamx{ public static void main(String[] args){ // 原始方法 PersonCreater creater1 = () -> { return new Person(); }; // 簡化方法 PersonCreater creater2 = () -> new Person(); // 構造方法的引用 PersonCreater creater3 = Person::new; Person a = creater3.getPersonNull(); Person a = creater3.getPersonDouble("張三",18); } } //接口中要說明 返回值類型 方法參數!!! interface PersonCreater{ Person gerPersonNull(); Person getPersonDouble(String name,int age); }
實現語法 -- 類::new
一、已知在一個 ArrayList 類中有若干個 Person 對象,講這些Person對象按照年齡進行降序排序;
public class Exercise{ public static void main(String[] args){ ArrayList<Person> list = new ArrayList<>(); list.add(new Person("張三",12)); list.add(new Person("李四",13)); list.add(new Person("韓梅梅",16)); list.add(new Person("趙四",6)); list.add(new Person("尼古拉斯凱奇",46)); list.add(new Person("Tony",54)); list.sort((o1,o2)-> o2.age-o1.age); } }
二、使用TreeSet排序
TreeSer<Person> set = new TreeSer<>((o1,o2)->o2.age-01.age); set.add(new Person("xiaoming",10)); set.add(new Person("wanggang",11)); set.add(new Person("zhaosi",8)); set.add(new Person("Nigu",43)); set.add(new Person("Tony",22)); set.add(new Person("poily",8)); set.add(new Person("Wngffei",40)); Sout(set); //運行結果:基本正確,可是隻有一個8歲的人;
代碼優化
TreeSer<Person> set = new TreeSer<>((o1,o2)->{ if(o1.age >= o2.age){ retrun -1; }else{ return 1; } }); set.add(new Person("xiaoming",10)); set.add(new Person("wanggang",11)); set.add(new Person("zhaosi",8)); set.add(new Person("Nigu",43)); set.add(new Person("Tony",22)); set.add(new Person("poily",8)); set.add(new Person("Wngffei",40)); Sout(set); //運行結果:正確;
public static void main(String[] args){ ArrayList<Interger> list -= new ArrayList<>(); Collection.addAll(list,1,2,3,4,5,6,7,8,9,0); list.forEach(ele->{ if(ele%2 == 0) Sout(ele); }); }
實現線程的實例化;
public static void main(String[] args){ Thread t = new Thread(()->{ for(int i=0;i<100;i++){ Sout(i); } }); t.start(); }
public static void (String[] args){、 //最經常使用的是Predicate、Consumer、Function、Supplier // Predicate<T> : 參數T ·返回值 boolean // IntPredicate : int-> boolean // LongPredicate : long->boolean // DoublePredicate : double // Consumer<T> : 參數T ·返回值 void // IntConsumer : int ->void // LongConsumer // DoubleConsumer // Function<T,R> : 參數T ·返回值 R // IntFuncation : int->R // LongFunction // DoubleFunction // IntToLongFunction: int->long // IntToDoubleFunction // LongToIntFunction // LongToDoubleFunction // DoubleToIntFunction // DoubleToLongFunction // Supplier<T> : 參數無 ·返回值 T // ……省略好多好多 // UnaryOperator<T> : 參數T ·返回值T // BinaryOperator : 參數T,T ·返回值T // BiFunction<T,U,R>: 參數T,U ·返回值R // BiPredicate<T,U> : 參數T,U ·返回值boolean // BiConsumer<T,U> : 參數T,U ·返回值void }
閉包
?
public static void main(String[] args){ int n = getNum().get(); Sout(n); //結果是10; } private static Supplier<Integer> getNum(){ int num = 10; return ()->{ return num; }; }
代碼二:
PSVM(String[] args){//public static void main int a = 10; Consumer<Integer> c = ele->{ Sout(a+1); }; c.accept(1);// 結果11 Consumer<Integer> c = ele->{ Sout(a++); }; c.accept();// 結果報錯,由於 閉包 中的變量必須是 final 的(也就是一個常量),因此不能修改這個值 }