前段時間的面試基本結(jié)束了,最后也有了不錯的結(jié)果骚亿,之后一段時間到入職打算好好整理一些東西诵闭。
想到馬上Java9也要出來了,Android也馬上支持Java8咪惠,自己都沒有好好整理過java8比較重要的知識點击吱,可以說8很多改動都是為了Lambda服務(wù)的,所以整理一下Lambda的內(nèi)容遥昧。
關(guān)于閉包
首先閉包是指覆醇,將當前作用域中的變量通過值或者引用的方式封裝到lambda表達式中,成為表達式的一部分炭臭,它使你的lambda表達式從一個普通的函數(shù)變成帶隱藏參數(shù)的函數(shù)永脓,當然閉包也可以不通過lambda實現(xiàn)
簡單理解為閉包就是定義在函數(shù)內(nèi)部的函數(shù)
Lambda 表達式與匿名類的區(qū)別
- Lambda 表達式與匿名類的主要不同在于兩者的編譯方法
- 對于匿名類,關(guān)鍵詞
this
解讀為匿名類鞋仍,而對于 Lambda 表達式常摧,關(guān)鍵詞this
解讀為寫就 Lambda 的外部類
什么時候用
任何可以接受一個函數(shù)式接口的地方都可以用lambda表達式
lambda作用在于
- 邏輯更緊湊
- 引入閉包,更簡潔的實現(xiàn)閉包
- 允許函數(shù)方法作為對象傳遞
函數(shù)式接口
定義
所謂的函數(shù)式接口凿试,也叫SAM接口(Single Abstract Method interfaces)排宰,當然首先是一個接口似芝,然后就是在這個接口里面只能有一個抽象方法
- 函數(shù)式接口里允許定義默認方法
- 函數(shù)式接口里允許定義靜態(tài)方法
- 函數(shù)式接口里允許定義java.lang.Object里的public方法
//以下都是不會報錯的
@FunctionalInterface
interface GreetingService{
void sayMessage(String message);
default void doSomeMoreWork1()
{
// Method body
}
static void printHello(){
System.out.println("Hello");
}
@Override
boolean equals(Object obj);
}
@FunctionalInterface注解
加不加@FunctionalInterface對于接口是不是函數(shù)式接口沒有影響,只是提醒編譯器去檢查該接口是否僅包含一個抽象方法板甘,用于編譯級錯誤檢查
新增java.util.function
- Predicate:用于判斷一個對象是否滿足某種條件党瓮,只有一個test抽象函數(shù),接受一個泛型T對象返回boolean
- Consumer:用于對對象進行消費操作盐类,只有一個accept抽象函數(shù)寞奸,接受一個泛型對象無返回
- Function:用于對象的轉(zhuǎn)換,只有一個apply抽象函數(shù)在跳,接受一個泛型T枪萄,返回一個泛型R
- Supplier:用于創(chuàng)建對象
- 還有一些衍生的可以自己看包下源碼
使用
使用相信大家都會一些,我就不列舉猫妙,網(wǎng)上大把的文章瓷翻,下面兩篇總結(jié)不錯
深入理解Java 8 Lambda(語言篇——lambda,方法引用割坠,目標類型和默認方法)
原理
Java 編譯器編譯 Lambda 表達式并將他們轉(zhuǎn)化為類里面的私有靜態(tài)函數(shù)
- 它使用 Java 7 中新加的
invokedynamic
齐帚,運行時調(diào)用LambdaMetafactory.metafactory
動態(tài)的生成內(nèi)部類,實現(xiàn)了接口 - 生成一個類私有靜態(tài)函數(shù)彼哼,在生成的實現(xiàn)類中調(diào)用
關(guān)于 Java 如何將 Lambda 表達式編譯為字節(jié)碼
interface Print<T> {
public void print(T x);
}
public class Lambda {
public static void PrintString(String s, Print<String> print) {
print.print(s);
}
public static void main(String[] args) {
PrintString("test", (x) -> System.out.println(x));
}
}
通過編譯最終等價于
interface Print<T> {
public void print(T x);
}
public class Lambda {
public static void PrintString(String s, Print<String> print) {
print.print(s);
}
private static void lambda$0(String x) {
System.out.println(x);
}
final class $Lambda$1 implements Print{
@Override
public void print(Object x) {
lambda$0((String)x);
}
}
public static void main(String[] args) {
PrintString("test", new Lambda().new $Lambda$1());
}
}
關(guān)于性能
16頁講到最差(capture)也和inner class一樣对妄, non-capture好的情況是inner class的5倍

但是在使用Stream的時候并不是所有情況都比普通迭代快的
下面這篇文章比較了各種情況下imperative code與functional code的性能表現(xiàn)
The effects of programming with Java 8 Streams on algorithm performance
關(guān)于Streams
Lambda最佳結(jié)合應(yīng)該就是Stream了,函數(shù)式編程與簡潔的結(jié)合
Java 8的Stream內(nèi)置了許多類似于數(shù)據(jù)庫的操作filter敢朱、sort剪菱、map、reduce等
用法就不貼了拴签,大把文章
官方的在這里
Stream優(yōu)點:
以數(shù)據(jù)庫操作數(shù)據(jù)的方式孝常,專注于如何做這個某個步驟,表達式的方式
高并發(fā)(看到map篓吁、reduce就應(yīng)該能想到了)
剛開始看Stream感覺和RxJava非常像茫因,但是仔細思索后有發(fā)現(xiàn)其實是兩個不同的東西,只是長得像而已杖剪。
下面這個最高票回答總結(jié)的非常好,總體來說
- stream是單次使用驰贷,是基于被動PULL
- rx是基于觀察者模式盛嘿,可多次訂閱,是基于主動PUSH