簡介
(下面的簡介也可以自己百度,一般進來的都是想知道怎麼去用,所以這裏主要也是重點在用法與實戰上)
Lambda表達式是Java SE 8中一個重要的新特性。lambda表達式允許你通過表達式來代替功能接口。 lambda表達式就和方法一樣,它提供了一個正常的參數列表和一個使用這些參數的主體(body,可以是一個表達式或一個代碼塊)。
Lambda表達式還增強了集合庫。 Java SE 8添加了lambda表達式。 在本文中,我們將從簡單到複雜的示例中見認識lambda表達式。
環境準備
如果還沒有安裝Java 8,那麼你應該先安裝才能使用lambda。 像NetBeans 和IntelliJ IDEA 一類的工具和IDE就支持Java
8特性,包括lambda表達式和其他特性。
android studio中使用lambda方法見: android studio中使用lambda
Lambda表達式的語法
基本語法:
(方法參數) -> 返回值
或
(方法參數) ->{ 方法內的語句; }
Lambda 簡單與漂亮的案例
//沒用使用lambda 的代碼
ArrayList<String> strs = new ArrayList<>();
Collections.sort(strs, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
下面是使用了lambda後的效果
//4行代碼只需要1句代碼就搞定
Collections.sort(strs, String::compareTo);
Lambda 開始學習
上面的案例在後面會介紹到的.
爲了更好的學習lambda 語法,我自己定義了一些接口,實現內部類,如下:
/**
* @Des: 內部方法帶1個參數 , 不帶返回值
*/
public interface IParmas1<A> {
void call(A a);
}
/**
* @Des: 內部方法帶2個參數 , 不帶返回值
*/
public interface IParmas2<A, B> {
void call(A a, B b);
}
/**
* @Des: 內部方法帶2個參數 , 帶返回值
*/
public interface IParmas2AndReturn<A, B, R> {
R call(A a, B b);
}
設置接口的監聽,實現內部類
//不帶返回值內部類,1個參數Demo
public void setOnIParmas1Listener(IParmas1 ipamr) {
}
//不帶返回值內部類,2個參數Demo
public void setOnIParmas2Listener(IParmas2 ipamr) {
}
//帶返回值內部類,2個參數Demo
public void setOnIParmas2AndReturnListener(IParmas2AndReturn ipamr) {
}
//配合demo1測試
public void demo1Test(Object o) {
}
//配合demo2測試
public void demo2Test(Object o1, Object o2) {
}
Lambda 雙冒號(::)的使用
lambda 還有一個很屌的寫法,看得我都覺得輕飄飄的feel都有了,
才發現原來java代碼可以這麼單純的,來看看吧,我也是看到這個寫法後才喜歡上lambda的.
那就是 lambda的雙冒號(::)寫法,lambda 雙冒號寫法前提條件是,方法接收的值是參數原值,沒有拼接其他數據,
額,不明白是吧,開始我也是雲裏霧裏,接着看下面解釋吧:
1.這是訂閱IParmas1 接口的一個監聽.
setOnIParmas1Listener(IParmas1 ipamr)
2.在{@link IParmas1} 接口中定義的方法參數(A a),也就是Object.
void call(A a);
3.因此在接收內部類方法參數,也就是demo1Test(Object o),該方法的參數也是obj
demo1Test(Object o)
4.這樣條件下就可以直接把下面的,案例1,寫成帶雙冒號lambda 語法了
setOnIParmas1Listener(this::demo1Test); //(案例1的lambda寫法)
多參數雙冒號寫法,見demo2的案例2.
Demo1 - 雙冒號
//TODO 案例1,方法內部實現使用統一參數類型 原始寫法
setOnIParmas1Listener(new IParmas1() {
@Override
public void call(Object o) {
ParmasImpl.this.demo1Test(o);
}
});
//lambda 寫法
setOnIParmas1Listener(this::demo1Test);
//TODO 案例2,不帶返回值 原始寫法
setOnIParmas1Listener(new IParmas1() {
@Override
public void call(Object s) {
ParmasImpl.this.demo2();
}
});
// 不帶返回值的lambda寫法
setOnIParmas1Listener(s -> demo2());
Lambda 匿名內部類的使用
使用lambda 來美化匿名內部類的高度,看起來簡單又優雅
lambda 會直接把整個內部類隱藏,只留下形參,而且有一點要注意,內部類使用lambda,
前提是,該內部類只有一個內部方法,如果有兩個或以上則使用不了lambda語法:
1. 空參數 寫法: () -> 內部類方法的實現.
2. 1參數(String) 寫法: s -> 內部類方法的實現.
需要注意的是當參數爲Void時,寫法與有1個參數的一樣
3. 2個參數(String,int) 寫法: (s,i) -> 內部類方法的實現.
lambda的 內部類寫法與泛型沒有太大關係,但是也要注意器參數是否被引用.
如果引用的話,其實lambda 是不推薦使用表達式的,但是也可以用,就是在用
的時候,他會自動將類型轉換成Object
如寫法1中: s 和 i 現在其實是 obj類型
寫法1:
setOnIParmas2Listener((s, i) -> {
System.out.println(s + "-----" + i);
});
寫法2:當然也可聲明類型
而且聲明參數類型,只有參數在兩個或以上纔可以,一個參數是不可以聲明的.
setOnIParmas2Listener((Object s,Object i) -> {
System.out.println(s + "-----" + i);
});
Demo2 - 匿名內部類
//TODO 案例1: 原始代碼
setOnIParmas2Listener(new IParmas2<String, Integer>() {
@Override
public void call(String s, Integer i) {
System.out.println(s + "-----" + i);
}
});
//使用lambda
//因爲上面其實是確定了類型的,被sout引用了,但是如果強制使用lambda的話
//會出現方法參數自動轉向默認obj類型
setOnIParmas2Listener((s,i)-> System.out.println(s + "-----" + i));
//TODO 案例2:多參數使用 lambda雙冒號
setOnIParmas2Listener(new IParmas2() {
@Override
public void call(Object o1, Object o2) {
ParmasImpl.this.demo2Test(o1, o2);
}
});
//使用lambda
setOnIParmas2Listener(this::demo2Test);
Lambda 方法帶返回值的使用
在有返回值的時候有兩種情況,下面使用帶兩個參數的內部方法來示範
1.內部方法直接返回,只有一個實現(方法/語句)
(s,i) -> null;
其實這個寫法就跟返回值是void的一樣,只是void返回值方法內實現一個(方法/語句)而已,
如demo1的案例2,中的lambda寫法.
s -> demo2()
2.內部方法返回, 2個以上實現(方法/語句)
(s,i) -> {
System.out.println("帶了一個sout的實現");
return null;
};
Demo2R - 帶返回值
//TODO 帶返回值的原始方法
setOnIParmas2AndReturnListener(new IParmas2AndReturn<String, Integer, Double>() {
@Override
public Double call(String s, Integer i) {
System.out.println("帶了一個sout的實現");
return null;
}
});
//使用lambda 寫法
setOnIParmas2AndReturnListener((s, i) -> {
System.out.println("帶了一個sout的實現");
return null;
});
實際代碼中實戰用法
在上面demo 中已經說過了lambda 的一些常用方法,
下面是在實際中 對集合數據排序時的用法:
首先我們分析下Collections.sort(); 功能中參數內部類方法.
內部類Comparator ,默認內部方法compare(s1,s2)參數類型是String,帶返回值int.
這樣我們心裏就大概知道lambda 該怎麼去寫或者這樣寫表達是上面意思.
//沒用使用lambda 的代碼
ArrayList<String> strs = new ArrayList<>();
Collections.sort(strs, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
//使用lambda 語法後,簡單好看
/**
* this::demo1Test 與 String::compareTo 區別
*
* 表達的就是當前類下的demo1Test(obj,obj)方法,
* 其實你如果直接引用compareTo 方法也是可以的,那你就不可以用this了,
* 而是使用String 對象,因此compareTo 在String 對象內.
*/
// 1.1 使用匿名內部類根據values 排序 strs
Collections.sort(strs, this::demoTest);
// 1.2 使用匿名內部類根據values 排序 strs
Collections.sort(strs, String::compareTo);
// 2 使用lambda根據values 排序 strs
Comparator<String> sortByName = (s1, s2) -> (s1.compareTo(s2));
Collections.sort(strs, sortByName);
// 3 也可以採用聲明形參的寫法:
Collections.sort(strs, (String s1, String s2) -> (s1.compareTo(s2)));
下面是demoTest(String,String)的方法
/**
* 提出比較的方法出來,方便lambda的雙冒號寫法調用
*/
private int demo1Test(String s1, String s2) {
return s1.compareTo(s2);
}
demo代碼: