再來看看Java8的新特徵——lambda表達式

Java8.jpg

什麼是lambda表達式?

能夠把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"));

->左邊的就是參數列表,->右邊的就是函數主體工具

函數式接口

爲何@FunctionalInterface註解修飾的類只能有一個抽象函數

查看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表達式使用局部變量必須是final的?

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表達式的用法

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、新的時間工具、默認方法等知識)。

相關文章
相關標籤/搜索