Lambda表達式和函數式編程


Lambda表達式和函數式編程

  https://www.cnblogs.com/bigbigbigo/p/8422579.html

  https://www.runoob.com/java/java8-lambda-expressions.html

函數接口是指內部只有一個接口函數的接口。

一、Lambda表達式

  • 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
  • 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
  • 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
  • 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。

在Lambda表達式之前,新建一個線程這樣寫:

new Thread(new Runnable(){
@Override
public void run(){
System.out.println("Thread run()");
}
}).start();

有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

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,對此應該並不陌生。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM