Lambda表達式和函數式編程html
http://www.javashuo.com/article/p-kcswmwel-bt.htmljava
https://www.runoob.com/java/java8-lambda-expressions.htmlgit
函數接口是指內部只有一個接口函數的接口。express
在Lambda表達式以前,新建一個線程這樣寫:編程
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("Thread run()");
}
}).start();ide
有Lambda表達式以後,則能夠這樣寫:
new Thread( () -> System.out.println("Thread run()") ).start();函數式編程
如上所示,Lambda表達式一個常見用法是取代(某些)匿名內部類,但Lambda表達式的做用不限於此。函數
Runnable run = () -> System.out.println("Hello World");// 1
ActionListener listener = event -> System.out.println("button clicked");// 2
Runnable multiLine = () -> {// 3
System.out.println("Hello ");
System.out.println("World");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4
BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5優化
Lambda表達式的另外一個重要用法,是和Stream一塊兒使用。
Stream is a sequence of elements supporting sequential and parallel aggregate operations。
Stream就是一組元素的序列,支持對這些元素進行各類操做,這些操做經過Lambda表達式指定。
能夠把Stream看做Java Collection的一種視圖,
就像迭代器是容器的一種視圖那樣(但Stream不會修改容器中的內容)。線程
下面例子展現了Stream的常見用法。
例子1
假設須要從一個字符串列表中選出以數字開頭的字符串並輸出,Java 7以前須要這樣寫:
List<String> list = Arrays.asList("1one", "two", "three", "4four");
for(String str : list){
if(Character.isDigit(str.charAt(0))){
System.out.println(str);
}
}
而Java 8就能夠這樣寫:
List<String> list = Arrays.asList("1one", "two", "three", "4four");
list.stream()// 1.獲得容器的Steam
.filter(str -> Character.isDigit(str.charAt(0)))// 2.選出以數字開頭的字符串
.forEach(str -> System.out.println(str));// 3.輸出字符串
上述代碼首先1. 調用List.stream()方法獲得容器的Stream,2. 而後調用filter()方法過濾出以數字開頭的字符串,3. 最後調用forEach()方法輸出結果。
使用Stream有兩個明顯的好處:
減小了模板代碼,只用Lambda表達式指明所需操做,代碼語義更加明確、便於閱讀。
將外部迭代改爲了Stream的內部迭代,方便了JVM自己對迭代過程作優化(好比能夠並行迭代)。
例子2
假設須要從一個字符串列表中,選出全部不以數字開頭的字符串,將其轉換成大寫形式,並把結果放到新的集合當中。Java 8書寫的代碼以下:
List<String> list = Arrays.asList("1one", "two", "three", "4four");
Set<String> newList =
list.stream()// 1.獲得容器的Stream
.filter(str -> !Character.isDigit(str.charAt(0)))// 2.選出不以數字開頭的字符串
.map(String::toUpperCase)// 3.轉換成大寫形式
.collect(Collectors.toSet());// 4.生成結果集
上述代碼
1.調用List.stream()方法獲得容器的Stream
2.調用filter()方法選出不以數字開頭的字符串
3.調用map()方法將字符串轉換成大寫形式
4.調用collect()方法將結果轉換成Set。
這個例子還向咱們展現了方法引用(代碼標號3處)以及收集器(代碼標號4處)的用法
經過這個例子咱們看到了Stream鏈式操做,即多個操做能夠連成一串。不用擔憂這會致使對容器的屢次迭代,由於不是每一個Stream的操做都會當即執行。Stream的操做分紅兩類,一類是中間操做(intermediate operations),另外一類是結束操做(terminal operation),只有結束操做纔會致使真正的代碼執行,中間操做只會作一些標記,表示須要對Stream進行某種操做。這意味着能夠在Stream上經過關聯多種操做,但最終只須要一次迭代。若是你熟悉Spark RDD,對此應該並不陌生。