前提
18年第一篇文章,祝各位新年快樂哈~
介紹Lambda之前,可以看下我們定義View點擊事件的一般做法
1. new View(this).setOnClickListener(new View.OnClickListener() {
2. @Override
3. public void onClick(View view) {
4. //...
5. }
6. });
這種回調模式在日常開發(fā)中很常見,但是隨之也暴露了一些不良的弊端
1、非抽象化晾虑,整個代碼有五行,其實實際邏輯只有在onclick里面仅叫,其他并不關心
2、無法使用外部非final屬性(這個遇到最多了)
3糙捺、this指針意義不明確
4诫咱、等等
所以,java8特性Lambda正好解決了這一系列問題洪灯,以下
new View(this).setOnClickListener(view->{
//.. doing
});
1.引入的lambda
lambda是在java8引入的函數表達式坎缭,其實是一種匿名的表達方式,Lambda表達式語法由參數列表签钩、->和函數體組成掏呼。函數體既可以是一個表達式也可以是一個代碼塊。
例如以下
# 表達式
()->8; // 這里8是return的返回結果铅檩,簡化了return
#代碼塊
()->{
//... 函數體
}
2.案例
說多不如做多憎夷,現(xiàn)在舉個??
2.1 線程利用lambada表達式
new Thread(()->{
//這里是線程運行的區(qū)域,實質是抽象化了Runnable的run方法
Log.i(TAG,"Thread is running...");
}).run();
2.2 多種情況利用lambada表達式
首先定義一個測試回調接口類
/**
* 這個類完全提供一些接口測試
*/
static class LambdaProvider{
TestInterface0 mTestInterface0; // 測試不帶參數與不帶返回值
TestInterface1 mTestInterface1;// 測試帶返回值
TestInterface2 mTestInterface2;// 測試待返回值昧旨、帶參數
TestInterface3 mTestInterface3;//測試拋出異常方法
public void setmTestInterface0(TestInterface0 mTestInterface0) {
this.mTestInterface0 = mTestInterface0;
}
public void setmTestInterface1(TestInterface1 mTestInterface1) {
this.mTestInterface1 = mTestInterface1;
}
public void setmTestInterface2(TestInterface2 mTestInterface2) {
this.mTestInterface2 = mTestInterface2;
}
public void setmTestInterface3(TestInterface3 mTestInterface3) {
this.mTestInterface3 = mTestInterface3;
}
public interface TestInterface0{
// 不帶參數拾给、不帶返回值
public void method();
}
public interface TestInterface1{
// 帶返回值
public int method1();
}
public interface TestInterface2{
// 帶參數
public int method2(int x);
}
public interface TestInterface3{
// 拋出異常方法
public void method3() throws Exception;
}
}
測試代碼
String value="";
LambdaProvider mLambdaProvider = new LambdaProvider();
mLambdaProvider.setmTestInterface1(()->2); // 直接返回2
mLambdaProvider.setmTestInterface1(()-> 2+4 ); // 直接返回計算表達式
mLambdaProvider.setmTestInterface1(()->{ // 直接返回作用域
Log.i(TAG,"setmTestInterface1 here...");
//... do something
String str = value; // 不用final就可以訪問到了
this.demo(); // this指針不再模糊
return 3;
});
// # 3 針對參數+返回值利用lambada表達式
mLambdaProvider.setmTestInterface2((x)->2); // 直接返回2
mLambdaProvider.setmTestInterface2((x)-> 2+4 ); //x 直接返回計算表達式
mLambdaProvider.setmTestInterface2((x)->{ // 使用形參x計算后返回
return x+2+4;
});
// #4 針對會拋出異常
mLambdaProvider.setmTestInterface3(()->{
throw new IllegalStateException("hi~");
});
3.高效的 Stream api
如果應用最小支持sdk24以上,Stream是非常高效的事情兔沃。當然國內sdk24以上的并不是占絕大多數蒋得,但是我們也可以先了解高效的Stream。
先小試牛刀,一般foreach遍歷list乒疏,我們一般會這么做
List<String> listSteam = Arrays.asList("0","1","2");
for (String i:listSteam){
//...
}
利用steam api额衙,我們可以這么做
listSteam.forEach(i->{
//...
});
反正我是佩服的??
什么是Stream?
借鑒某大神的說明,“Stream不是集合元素窍侧,它也不是數據結構追驴、不能保存數據,它更像一個更高級的Interator疏之。Stream提供了強大的數據集合操作功能殿雪,并被深入整合到現(xiàn)有的集合類和其它的JDK類型中。流的操作可以被組合成流水線(Pipeline)”
使用Stream可以做很多事情锋爪,如果以后會接觸到rxjava,你會發(fā)現(xiàn)很多操作符是借鑒了Stream里面流的概念丙曙。在Stream操作中,都會涉及一個步驟
上流(Stream)->處理->下流結果(Stream)
舉個例子??
首先創(chuàng)建一個測試model其骄,并且實例了一個數組
class Model{
public String type;//"1","2" 用于區(qū)別類型
public String name;
public Model(String type, String name) {
this.type = type;
this.name = name;
}
@Override
public String toString() {
return "Model (type: " + type +" name: "+name+")";
}
}
List<LambdaProvider.Model> listSteam = Arrays.asList(new LambdaProvider.Model("1","siven0"),
new LambdaProvider.Model("2","siven1"),new LambdaProvider.Model("2","siven2")
,new LambdaProvider.Model("2","siven3"));
場景1:
只提取type是2的數據到新數組
List<LambdaProvider.Model> newList = listSteam.stream()
.filter(s->s.type.equals("2"))
.collect(Collectors.toList());
newList.forEach(s-> consoleInput(TAG,"stream newList: "+s));
Collectors是負責接收上面?zhèn)鬟f過來的流亏镰,tolist是將傳遞過來的流重新組合成list
filter是負責過濾上面?zhèn)鬟f過來的流,里面return是一個布爾值
場景2:
提取ype是2的數據拯爽,并且將流轉化為其他數據的流后組成新的數組
List<String> listIndex = listSteam.stream()
.filter(s->s.type.equals("2"))
.map(s->s.name)
.collect(Collectors.toList());
listIndex.stream().forEach(s-> consoleInput(TAG,"stream listIndex: "+s));
map組要做流轉化索抓,上面的場景是接收到Model的流后,通過訪問實體的對象name轉化為字符串流(下面用map我會貼更加詳細的說明)
map的各種玩法(建議閱讀):
// 玩玩map轉化
List<String> stringList = Arrays.asList("1","2","3"); // 隨便申請一個list
consoleInput(TAG,"玩玩map轉化 ----- flatmap ");
List<String> tmp0 = stringList.stream()
.flatMap((s)->{
String str = (String) s + " - 轉化(flatmap)";
consoleInput(TAG,"轉化前 "+s + "毯炮,轉化后 " + str);
List<String> result = new ArrayList<>();
result.add(str);
return result.stream();
})
// 為了方便讀者閱讀逼肯,我用非lambda表達式
// .flatMap(new Function<String, Stream<String>>() {
// @Override
// public Stream<String> apply(String s) {
// String str = (String) s + " - 轉化";
// consoleInput(TAG,"轉化前 "+s + "轉化后 " + str);
// List<String> result = new ArrayList<>();
// result.add(str);
// return result.stream();
// }
// })
.collect(Collectors.toList());// 流收集起來
consoleInput(TAG,"轉換后結果輸出 ");
tmp0.stream().forEach(c->consoleInput(TAG,"-> "+c));
consoleInput(TAG,"玩玩map轉化 ----- map ");
tmp0 = stringList.stream()
.map((s)->{
String str = (String) s + " - 轉化(map)";
consoleInput(TAG,"轉化前 "+s + ",轉化后 " + str);
return str;
})
// 為了方便讀者閱讀桃煎,我用非lambda表達式
// .map(new Function<String, String>() {
// @Override
// public String apply(String s) {
// String str = (String) s + " - 轉化(map)";
// consoleInput(TAG,"轉化前 "+s + "篮幢,轉化后 " + str);
// return str; }
// })
.collect(Collectors.toList());// 收集
consoleInput(TAG,"轉換后結果輸出 ");
tmp0.stream().forEach(c->consoleInput(TAG,"-> "+c));
consoleInput(TAG,"玩玩map轉化 ----- sum ");
int sum = stringList.stream()
.mapToInt(s->Integer.valueOf(s)) // map轉int
.sorted() // 排序
.sum();
consoleInput(TAG,"轉換后結果輸出 "+sum);
這里要思考的就是flatMap與map有什么區(qū)別了,從方法看flatMap是object->stream<T>为迈。而map是object->object三椿。如果你的場景是希望自己的上流傳遞有多次處理邏輯,并不希望馬上得到下流的結果葫辐。那flatMap更滿足你需求了搜锰。如果是直接A到B,明確的結果耿战,map也許更適合你
4.總結
年終了~祝大家工作順利蛋叼,事業(yè)進步!
by siven
2018.1.5