能夠把Lambda表達式理解爲簡潔地表示可傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。java
好比說new一個Thread的傳統寫法以下app
Thread t = new Thread(new Runnable() { public void run(){ System.out.println("Hello world"); } });
那麼利用lambda表達式的寫法就是函數
Thread t = new Thread(() -> System.out.println("Hello world"));
->
左邊的就是參數列表,->
右邊的就是函數主體工具
查看Java8的源碼,被@FunctionalInterface修飾的函數叫作函數式接口,例如Predicate
,這些類每每只有一個抽象函數,那是由於「Lambda表達式理解爲簡潔地表示可傳遞的匿名函數
」,直接使用的匿名函數的時候沒有指定函數名稱,因此,若是有兩個及以上抽象函數的時候,虛擬機就不知道你要執行哪一個方法了,如上例中Runnable的run()方法,咱們參數列表部分只使用了(),並無聲明調用的函數名。spa
JDK自帶的函數式接口都在java.util.function路徑下,經常使用的有線程
public interface Predicate<T>{ boolean test (T t); } public interface Consumer<T> { void accept(T t); } public interface Function<T, R> { R apply(T t); } ...
//源碼部分 @FunctionalInterface public interface Predicate<T>{ boolean test(T t); } //方法構建 public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> results = new ArrayList<>(); for(T s: list){ if(p.test(s)){ results.add(s); } } return results; } //使用示例,經過filter方法,篩選出String不爲空的數據 Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
其餘函數式接口使用示例3d
lambda表達式主體部分除了使用參數列表的數據,還可使用lambda表達式外部的局部變量,可是這些局部變量只能聲明一次,不然就會報錯。code
int portNumber = 1337; //此時會報錯,portNumber必須被final修飾 Runnable r = () -> System.out.println(portNumber); portNumber = 31337;
由於lambda表達式主體可看做是匿名內部類,訪問外部局部變量是須要final的。從線程的角度來講,就是局部變量是一個線程(假設叫線程A),lambda表達式主體是另一個線程(線程B),當線程A結束的時候,線程B還要訪問線程A的數據,確定是不行的,因此線程B中的變量實質上不是指向線程A中的變量,而是拷貝了一份出來,因此必須保證拷貝出來的數據是不能夠改變的。對象
lambda表達式還有一個很是方便的地方,就是方法引用,能夠經過類名::方法名
的形式直接使用方法。blog
例如
//靜態方法 Integer::parseInt //對象的普通方法 String::length //構造方法 Apple::new
lambda表達式還能夠鏈式調用,同時擁有與或非(negate、and和or)的邏輯判斷
//鏈式調用 inventory.sort(comparing(Apple::getWeight) .reversed() .thenComparing(Apple::getCountry)); //非 Predicate<Apple> notRedApple = redApple.negate(); //與 Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150); //或 Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150) .or(a -> "green".equals(a.getColor()));
Function函數接口提供了兩個方法對數據作連續操做
,andThen和compose方法。
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.andThen(g); int result = h.apply(1); //輸出3 ==> )(1*2)+1
andThen方法至關於先執行f函數,再執行g函數。
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.compose(g); int result = h.apply(1); //輸出4 ==> (1+1)*2
compose方法至關於先執行g函數,再執行f函數。
接下來會梳理流的相關知識點、和其餘(注入Optionnal、新的時間工具、默認方法等知識)。