java 8 lambda—第二章—lambda運算式__java

來源:互聯網
上載者:User
第二章:lambda運算式
java8中最大的變化就是引入了lambda運算式,一種緊湊的傳遞行為的方式,這也是本書剩下部分所要討論的內容,讓我們進入其中吧。


編寫第一個lambda運算式
swing是一個平台無關的gui庫,在該庫中,有很多常見的習慣,比如為了知道使用者點點擊了什麼,註冊一個事件監聽器,這個事件監聽器可以執行一些操作響應使用者的輸入。
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("button clicked");
}
})
在該例子中,我們建立了一個對象實現了ActionListener介面,該介面只有一個方法actionPerformed(),當使用者點擊了按鈕之後,這個方法會被調用,該匿名內部類提供了該方法的實現。


匿名內部類是為了讓java程式員傳遞行為和傳遞資料一樣容易,不幸的是,他們並不容易,為了調用處理邏輯的代碼仍然有四行模板代碼,重複的模板代碼並不是唯一的問題,這種代碼也難以閱讀,我們並不想傳遞一個對象,而僅僅只需要傳遞某種行為,在java8中我們可以寫得更簡潔
button.addActionListener(event -> System.out.println("button cliecked"));


不同於傳遞一個實現某個介面的對象,我們傳遞了一段沒有命名函數的代碼,event是參數,同匿名內部類的參數一樣, ->將參數和lambda運算式的內容體分開。同匿名內部類做法另外一種不同就是,我們申明變數的方式,之前,我們需要顯示申明類型ActionEvent,在該例中,我們不需要提供類型,編譯也能通過,在這背後發生的是javac從上下文擷取event類型,此處是從addActionListener簽名中擷取,這意味著你不需要顯示申明其類型,我們之後會更加詳細討論這種設計,首先讓我們看看編寫lambda運算式幾種不同的方法。


如何在正確的場合使用lambda運算式。
下面有幾個使用lambda運算式的例子
①Runnable noArguments = () -> System.out.println("hello world");
②ActionListener oneArgument = event -> System.out.println("button click");
③Runnable multiStatement = () ->{
System.out.print("hello");
System.out.println(" world");
}
④BinaryOperator<Long> add = (x, y) -> x + y;
⑤BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;


①展示了在沒有參數的情況下如何使用lambda,可以使用一對空的小括弧來表示沒有參數,這是一個實現了Runnable的lambda的運算式,該介面只有一個方法run(),該方法不接受任何參數,且返回void.
②展示了只有一個參數的lambda的運算式。
不同於只包含一條運算式的lambda,③包含了一個代碼塊,包含在一個大括弧中,代碼塊同平常的方法類似,在結束之前可以返回結果或者拋出異常,
④包含了多個參數,這種情況下有必要考慮如何閱讀這條運算式,這行代碼沒有相加兩個數,它建立了一個函數相加兩個數,add這個變數並不是兩個數的和,而是一個相加兩個數的函數。
⑤目前為止,所有的lambda運算式參數類型都是由編譯器確定,這非常棒,但是有些時候我們需要明確參數類型。


上述所有運算式都表明lambda運算式依賴於上下文,由編譯器去判斷,這種做法也不完全新創的,在example2-4中數組的初始化依賴於上下文環境,還有null,只有把它分配的時候才知道其類型。
final String[] array = {"hello", "world"};




Using Values
你以往使用匿名內部類的時候,你可能遇到這種情況,在內部類中你想使用外部的變數,需要把外部變數申明為final類型,變數申明為final意味著不能將該變數指向其他對象。
final String name = getUserName();
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("hi"+name);
}
})
在java8中,這種限制有所放鬆,可以引用非final的參數,雖然沒有申明為final類型,但是必須當做final類型看待,不能去改變其所指的對象,否則會報錯。
String name = getUserName();
button.addActionListener(event -> System.out.println("hi" + name));
如果多次為一個變數賦值,並且單算在lambda運算式中進行引用,那麼會得到一個變異錯誤。
String name = getUserName();
name = formatUserName(name);
button.addActionListener(event -> System.out.println("hi" + name));
這也是為什麼人們把lambda運算式當做閉包看待,在程式設計語言的爭論中,有許多關於java是否有閉包的爭論,因為其只能引用final變數,為了避免這一個無端的爭論,我在本書中將他們稱之為lambda運算式。但是無論我如何稱呼他們,我已經提到過lambda運算式是靜態類型的,因此讓我們研究運算式本身:他們稱之為函數式介面。




函數式介面
函數式介面是指的只有一個抽象方法的介面,被當做是lambda運算式的一種類型使用。
在java中,所有的參數都有類型,如果我們傳入3到一個方法中,這個參數是int類型,那麼lambda是什麼類型的呢。


類型討論。
某些情況下,需要提供確切的類型標誌,我的建議是你和你的團隊怎麼易讀怎麼做。有的時候不標明類型讓其看起來更加簡潔,有時候加上類型標誌讓其更加明顯。我發現,起初加上類型可能看起來很有用,但是之後可能你只會在必要的時候才會加上,本章將會提供幾個原則讓你很容易辨別出是否必要加上。
類型的討論其實是java7中類型討論的延續。
Map<String, Integer> oldWordCount = new HashMap<String, Integer>();
Map<String, Integer> diamonWordCounts = new HashMap<>();
對於變數oldWordCount我們明確指明了泛型的類型,但是diamonWordCounts使用了diamond operator,泛型型別並沒有指出,編譯器會指定其類型。
如果你直接傳遞一個建構函式到方法中,編譯器也能指出泛型型別,同樣的java7允許空出建構函式的泛型,java8允許lambda運算式的參數類型。
其實沒有什麼魔法,java編譯器在lambda運算式上下文中尋找參數確定的類型。
讓我們通過幾個例子更加深入討論。
在下面兩種情況下,我們傳入一個參數到一個函數介面中,因此我們很容易確定兩者的區別。
第一個例子:
Predicate<Integer> atLeast5 = x -> x >5
不同於之前的ActionListener樣本,Predicate是一個有傳回值的lambda運算式,這裡運算式的內容為x > 5,運算式的值作為lambda運算式的傳回值。
我們可以看到Predicate有一個泛型參數,上一個運算式中我們傳入一個int值,java編譯器會檢測傳回值是否為一個boolean值。
public interface Predicate<T>{
boolean test(T t);
}


讓我們看看另外一個更加複雜的例子:
BinaryOperator介面
BinaryOperator<Long> addLongs = (x, y) -> x+y;
這個介面有兩個參數以及一個傳回值,兩個參數類型相同,在執行個體中我們使用的參數類型為Long類型,但是如果不提供足夠的資訊編譯器就會返回一個變異錯誤,例如在下面的一個運算式中就會拋出變異錯誤
BinaryOperator add = (x, y) -> x + y;




總結:
1.lambda運算式沒有命名,用來像傳遞資料一樣傳遞操作。
2.函數介面指的是只有一個抽象方法的介面,被當做是lambda運算式的類型。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.