1. 程式人生 > >第三章(1) Lambda表示式

第三章(1) Lambda表示式

1.lambda表示式的基本形式

      在上一章中,你瞭解了利用行為引數化來傳遞程式碼有助於應對不斷變化的需求。它允許你定義一個程式碼塊來表示一個行為,然後傳遞它。你可以決定在某一事件發生時(例如單擊一個按鈕)或在演算法中的某個特定時刻(例如篩選演算法中類似於“重量超過150克的蘋果”的謂詞,或排序中的自定義比較操作)執行該程式碼塊。一般來說,利用這個概念,你就可以編寫更為靈活且可重複使用的程式碼了。但你也看到,使用匿名類來表示不同的行為並不令人滿意:程式碼十分囉嗦,這會影響程式設計師在實踐中使用行為引數化的積極性。在本章中,我們會教給你Java 8中解決這個問題的新工具——Lambda表示式。它可以讓你很簡潔地表示一個行為或傳遞程式碼。現在你可以把Lambda表示式看作匿名功能,它基本上就是沒有宣告名稱的方法,但和匿名類一樣,它也可以作為引數傳遞給一個方法。我們會展示如何構建Lambda,它的使用場合,以及如何利用它使程式碼更簡潔。我們還會介紹一些新的東西,如型別推斷和Java 8 API中重要的新介面。最後,我們將介紹方法引用(method ref-erence),這是一個常常和Lambda表示式聯用的有用的新功能。

      可以把Lambda表示式理解為簡潔地表示可傳遞的匿名函式的一種方式:它沒有名稱,但它有引數列表、函式主體、返回型別,可能還有一個可以丟擲的異常列表。這個定義夠大的,讓我們慢慢道來。

1.匿名——我們說匿名,是因為它不像普通的方法那樣有一個明確的名稱:寫得少而想得多!

2.函式——我們說它是函式,是因為Lambda函式不像方法那樣屬於某個特定的類。但和方法一樣,Lambda有引數列表、函式主體、返回型別,還可能有可以丟擲的異常列表。

3.傳遞——Lambda表示式可以作為引數傳遞給方法或儲存在變數中。

4.簡潔——無需像匿名類那樣寫很多模板程式碼。

     那麼,咱們再通過一個例項,來再次看看這個lambda表示式,書接上文,我們現在要對第二章的豬按體重排一下序,那麼在有lambda表示式之前,我們是這麼做的:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Pig> pigList = new ArrayList<Pig>();
		pigList.add(new Pig("黑色", 120));
		pigList.add(new Pig("白色", 300));
		pigList.add(new Pig("黑色", 208));
		pigList.add(new Pig("白色", 188));
		Collections.sort(pigList, new Comparator<Pig>() {

			@Override
			public int compare(Pig o1, Pig o2) {
				// TODO Auto-generated method stub
				return o1.getWeight().compareTo(o2.getWeight());
			}
		});
		for(Pig pig : pigList) {
			System.out.println(pig.getWeight());
		}
   
	}

結果如下:

那麼有了lambda表示式後呢,我們是這樣的:

Collections.sort(pigList, (Pig a1, Pig a2) -> a1.getWeight().compareTo(a2.getWeight()));

當然,你也可以這樣寫,看你心情:

Comparator<Pig> byWeight = (Pig p1,Pig p2) -> p1.getWeight().compareTo(p2.getWeight());
Collections.sort(pigList, byWeight);

 暴露一下介面,方便清楚程式碼的來龍去脈和在IDE中的程式碼追蹤,否則按第一種寫法,你在ide中例如eclipse無法通過按住ctrl點選而找到介面。

我們剛剛給你展示的lambda有三個部分:

1.引數列表:這裡它採用了Comparator中介面compare方法的引數,兩個泛型。

2.箭頭——箭頭->把引數列表與Lambda主體分隔開。

3.Lambda主體——比較兩個pig的重量。表示式就是Lambda的返回值了。

為了進一步說明,下面給出了Java 8中五個有效的Lambda表示式的例子:
 

1.(String s) -> s.length() 第一個Lambda表示式具有一個String型別的引數並返回一個int。Lambda沒有return語句,因為已經隱含了return。

2.(Apple a) -> a.getWeight() > 150 第二個Lambda表示式有一個Apple 型別的引數並返回一個boolean(蘋果的重量是否超過150克)

3.(int x, int y) -> { System.out.println("Result:");

                     System.out.println(x+y); }
第三個Lambda表示式具有兩個int型別的引數而沒有返回值(void返回)。注意Lambda表示式可以包含多行語句,這裡是兩行。

4.() -> 42 第四個Lambda表示式沒有引數,返回一個int。

5.(Apple a1, Apple a2) ->a1.getWeight().compareTo(a2.getWeight()) 第五個Lambda表示式具有兩個Apple型別的引數,返回一個int:比較兩個Apple的重量

 lambda表示式的基本語法是:

(parameters引數) -> expression表示式

(parameters) -> { statements(語句); }

我們看到lambda表示式非常簡單,下面我們做一個測試,看看你是否真正掌握lambda表示式:

請找出下列無效的lambda表示式:

1.()->{}

2.()->"fuck"

3.()->{return "fuck";}

4.(int i) ->return i+3

5.(String s)-> {"泥煤的";}

顯然只有4和5是無效的。

(1)這個Lambda沒有引數,並返回void。它類似於主體為空的方法:public void run() {}。

(2)這個Lambda沒有引數,並返回String作為表示式。

(3)這個Lambda沒有引數,並返回String(利用顯式返回語句)。

(4)return是一個控制流語句。要使此Lambda有效,需要使花括號。

(5)“泥煤的”是一個表示式,不是一個語句。要使此Lambda有效,你可以去除花括號和分號,如下所示:(String s) -> "泥煤的"。或者如果你喜歡,可以使用顯式返回語句,如下所示:(String s)->{return "泥煤的";}。

2.函式式介面

     我們已經很好的瞭解了lambda表示式,那麼lambda在哪裡使用呢?你可以在函式式介面中使用lambda表示式。那麼什麼叫做lambda表示式呢?譬如我們第二章關於豬的篩選條件介面

public interface PigPredicate {
 
	public Boolean test(Pig pig);
}

這就是一個函式式介面,你可以對其使用lambda實現之並將其作為引數傳入其他方法使用其test方法對豬進行篩選。下面我們就來詳細說明函式式介面。

      那麼首先,什麼是函式式介面呢?一言以蔽之,函式式介面就是只定義一個抽象方法的介面。你已經知道了Java API中的一些其他函式式介面,如我們在第2章中談到的Comparator和Runnable。

      而我們的lambda表示式,就可以看作是一個函式式介面的例項!

     所謂只有一個抽象方法,並不是指你僅僅在介面中看到的那種接口裡面只寫了一個抽象方法,那就是函式介面,別忘了介面之間還有繼承關係,如果一個介面繼承了另一個介面,而他本身也擁有自己的抽象方法,那麼它就不是函式式介面。

    那麼有沒有什麼方法,能讓我們在編寫函式式介面的時候,能夠避免這種錯誤呢?答案是有的,那就是通過@FunctionalInterface註解,這個註解能夠幫助我們檢測你編寫的介面是不是函式式介面

3.函式描述符

     函式式介面的抽象方法的簽名基本就是lambda的簽名,我們管這種抽象方法叫做函式描述符。例如,Runnable介面可以看作一個什麼也不接受什麼也不返回(void)的函式的簽名,因為它只有一個叫作run的抽象方法,這個方法什麼也不接受,什麼也不返回(void)。通過上面的描述,我們知道你的lambda表示式必須符合這種介面的函式描述符才能有效。

4.JAVA8 api為我們提供的函式式介面

   Java 8的庫設計師幫你在java.util.func-tion包中引入了幾個新的函式式介面。我們接下來會介紹Predicate、Consumer和Function為了便於文章檢索,我在這裡把它放入下一章講解。

相關推薦

1 Lambda表示式

1.lambda表示式的基本形式       在上一章中,你瞭解了利用行為引數化來傳遞程式碼有助於應對不斷變化的需求。它允許你定義一個程式碼塊來表示一個行為,然後傳遞它。你可以決定在某一事件發生時(例如單擊一個按鈕)或在演算法中的某個特定時刻(例

1 Lambda表示式

1.lambda表示式的基本形式       在上一章中,你瞭解了利用行為引數化來傳遞程式碼有助於應對不斷變化的需求。它允許你定義一個程式碼塊來表示一個行為,然後傳遞它。你可以決定在某一事件發生時(例如單擊一個按鈕)或在演算法中的某個特定時刻(例如篩選演算法中類似於“重量超

3 lambda表示式型別檢查、型別推斷以及區域性變數

     1.型別檢查      當我們在之前第一次提到lambda表示式的時候,說它可以為函式式介面生成一個例項。然而,Lambda表示式本身並不包含它在實現哪個函式式介面的資訊。為了全面瞭解Lambda表示式,你

安卓學習1《第一行程式碼》

佈局控制元件 一、TextView 1、<TextView>可以說是Android中最簡單的一個控制元件,主要用於在介面上顯示一段文字資訊。 2、指定控制元件的寬度和高度 android:layout_width="match_parent" android:layout

SQL——1

3.1 SQL概述 3.1.1  SQL的特點 綜合統一;高度非過程化;面向集合的操作方式;以同一種語法結構提供多種使用方式;語言簡結,易學易用。                                                        高度非過高度

人工智慧1——無資訊搜尋盲目搜尋 附書本資料

摘要 本章旨在講清楚:1)搜尋問題如何形式化;2)樹搜尋,圖搜尋,及演算法評估;3)一些搜尋策略:寬度優先,一致代價,深度優先,深度受限,迭代加深,雙向搜尋。 前言 這一章說的是Agent,但是是搜尋Agent,所以主要講的是各種搜尋演算法(

6複合Lambda表示式

     你可以把多個簡單的Lambda複合成複雜的表示式。比如,你可以讓兩個謂詞之間做一個or操作,組合成一個更大的謂詞。而且,你還可以讓一個函式的結果成為另一個函式的輸入。你可能會想,函式式介面中怎麼可能有更多的方法呢?(畢竟,這違背了函式式介面的定義啊!)竅門在於

4擴充套件------lambda表示式與閉包(關於lambda使用區域性變數的補充)

      關於閉包,掌握js的童鞋會更加的瞭解,但是如今,我們在學習java8的lambda的時候,上一章提到lambda關於使用區域性變數的時候,書中提到了lambda與閉包的問題。他的原話是這麼說的:      你可能已經聽說過閉

1.4linux下部署tensorflow環境

一、在安裝好 anaconda後,即可通過anaconda安裝tensorflow anaconda安裝請參考:http://blog.csdn.net/lzc4869/article/detail

1 流Stream介紹

1.使用流的好處   流是Java API的新成員,它允許你以宣告性方式處理資料集合(通過查詢語句來表達,而不是臨時編寫一個實現,例如你要在集合中篩選一個紅色的蘋果,你可以用類似於sql式的查詢結構來說明你要幹什麼就可以了,而無需想著如何的去實現它,比如使用for迴圈+if判

5方法引用

1.方法引用初探      方法呼叫可以被看作僅僅呼叫特定方法的lambda表示式的一種快捷寫法。如果一個Lambda代表的只是“直接呼叫這個方法”,那最好還是用名稱來呼叫它,而不是去描述如何呼叫它。事實上,方法引用就是讓你根據已有的方法實現來建立Lambda表示式

2 JAVA8 api為我們提供的函式式介面

   咱們書接上回,上回咱們說到,Java 8的庫設計師幫你在java.util.function包中引入了幾個新的函式式介面。我們接下來會介紹Predicate、Consumer和Function。     1.Predicate(謂詞)

安卓學習2《第一行程式碼》

一、佈局的線性佈局<LinearLayout 1、示例: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal"

安卓學習3《第一行程式碼》

一、建立自定義標題欄 1、以線性佈局編寫程式碼。除了之前學過的設定控制元件對齊方式控制元件大小還有控制元件地址命名外,android:text設定控制元件文字內容,android:textColor設定控制元件底色,android:background設定背景,android:layout_ma

C++primer 習題1

4.7編寫程式碼實現一個數組賦值給另外一個數組,然後將這段程式碼改用vector實現。考慮如何將一個vector 賦值給另一個vector。 int main() { int a[3] = { 1,2,3 }; int b[3]; cout << "array :" <&l

TensroFlow學習——

MINIST數字識別問題 全連線層實現手寫數字識別 採用了L2正則化、滑動平均模型和指數衰減學習率 訓練結果為:訓練集93%,驗證集95.36%,測試集95.01% 第一部分:前向傳播和網路引數 # 定義前向傳播和神經網路中的引數 import tensorflow as tf

TensroFlow學習——

MINIST數字識別問題 卷積神經網路實現手寫數字識別 採用了L2正則化、滑動平均模型,固定學習率 訓練結果為:訓練集100%,驗證集99.4%,測試集99.43% 第一部分:前向傳播和網路引數 # 定義前向傳播和神經網路中的引數 import tensorflow as tf

Java四天——核心技術2

繼續第三章的學習。。。 運算子 運算子+、-、*、/表示加、減、乘、除運算 %求餘操作 /運算 兩個運算元都是整數時,表示整數除法;否則,表示浮點數除法 例:15/2=7 15%2=1 15.0/2=7.5 整數被0除會產生

Java核心技術--5

控制流程 條件語句+迴圈結構 控制流程 條件語句 迴圈語句 switch語句(判斷多個值) 塊 用 { }括起來的若干條Java語句 塊可巢狀在另一個塊中 public static void main(String[] args)

計算機組成原理筆記-哈工大

1.匯流排的基本概念 匯流排:是連線各個部件的資訊傳輸線,是各個部件共享的傳輸介質。 匯流排的傳輸方式: 序列——長距離 ,一次傳輸1位            並行——短距離,一次傳輸n位 2.匯流排分類 1.片內匯流排   晶片內部的匯流排