【java基礎(三十九)】lambda表達式(一)

lambda表達式,這是這些年來Java語言最讓人激動的一個變化。

爲什麼引入lambda表達式

lambda表達式是一個可傳遞的代碼塊,可以在以後執行一次或多次。具體介紹語法之前,我們先退一步,觀察一下我們在Java中的哪些地方用過這種代碼塊。

之前我們瞭解瞭如何按指定時間間隔完成工作。將這個工作放在一個ActionListener的actionPerformed方法中:

class Worker implements ActionListener {
	public void actionPerformed(Action event) {
		...
	}
}

想要反覆執行這個代碼時,可以構造Worker類的一個實例。然後把這個實例提交到一個Timer對象。這裏的重點是actionPerformed方法包含希望以後執行的代碼。

或者可以考慮如何用一個定製比較器完成排序。如果想按長度而不是默認的字典順序對字符串排序,可以想sort方法傳入一個Comparator對象:

class LengthComparator implements Comparator<String> {
	public int compare(String first, String second) {
		return first.length() - second.length();
	}
}
...
Arrays.sort(strings, new LengthComparator());

compare方法不是立即調用。實際上,在數組完成排序之前,sort方法會一直調用compare方法,只要元素的順序不正確就會重新排列元素。將比較元素所需的代碼放在sort方法中,這個代碼將於其餘的排序邏輯繼承。

這兩個例子有一些共同點,都是將一個代碼塊傳遞到某個對象(一個定時器,一個sort方法)。這個代碼塊會在將來某個時間調用。

到目前爲止,在Java中傳遞一個代碼段並不容易,不能直接傳遞代碼段。Java是一種面嚮對象語言,所以必須構造一個對象,這個對象的類需要有一個方法能包含所需的代碼。

在其他語言中,可以直接處理代碼塊。Java設計者很長時間以來一直拒絕增加這個特性,畢竟,Java的強大之處就在於其簡單性和一致性。如果只要一個特性能夠讓代碼稍簡潔一些,就把這個特性增加到語言中,這個語言很快就會變得一團糟,無法管理。不過,在另外那些語言中,並不只是創建線程或註冊按鈕點擊事件處理器更容易;它們的大部分API都很簡單、更一致而且更強大。在Java中,也可以編寫類似API利用類對象實現特定的功能,不過這種API使用可能很不方便。

就現在來說,問題已經不是是否增強Java來支持函數式編程,而是要如何做到這一點。設計者們做了多年的嘗試,終於找到一種適合Java的設計。

lambda表達式的語法

我們考慮一下剛纔說的排序例子。我們傳入代碼來檢查一個字符串是否比另一個字符串短:

first.length() - second.length();

first和second是什麼呢?它們都是字符串,Java是一種強類型語言,所欲我們還要指定它們的類型:

(String first, String second) -> first.length() - second.length();

這就是你看到的第一個lambda表達式。lambda表達式就是一個代碼塊,以及必須傳入代碼的變量規範。

你已經見過Java中的一種lambda表達式形式:參數,箭頭(->)以及一個表達式。如果代碼要完成的計算無法放在一個表達式中,就可以像寫方法一樣,把這些代碼放在{}中,幷包含顯式的return語句。如:

(String first, String second) - > {
	if (first.length() < second.length()) return -1;
	else if (first.length() > second.length()) return 1;
	else return 0;
}

即使lambda表達式沒有參數,仍然要提供空括號,就像無參數方法一樣:

() -> {
	for (int i = 100; i >=0; i--)
		System.out.println(i);
}

如果可以推導出一個lambda表達式的參數類型,則可以忽略其類型。如:

Comparator<String> comp = (first, second) -> first.length() - second.length();

在這裏,編譯器可以推導出first和second必然是字符串,因爲這個lambda表達式將賦給一個字符串比較器。

如果方法只有一個參數,而且這個參數的類型可以推導得出,那麼甚至還可以省略小括號:

ActionListener listener = event -> System.out.println("The time is " + new Date());

無需指定lambda表達式的返回類型。lambda表達式的返回類型總是會由上下文推導得出,如:

(String first, String second) -> first.length() - second.length();

可以在需要int類型結果的上下文中使用。

實例

package cn.freedompc.lambda;

import java.util.Arrays;
import java.util.Date;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class LambdaTest {

	public static void main(String[] args) {
		String[] planets = new String[] {"Mercury", "Venus", "Earth", "Mars", 
				"Jupiter", "Saturn", "Uranus", "Neptune"};
		System.out.println(Arrays.toString(planets));
		System.out.println("Sorted in dictionary order:");
		Arrays.sort(planets);
		System.out.println(Arrays.toString(planets));
		System.out.println("Sorted by length:");
		Arrays.sort(planets, (first, second) -> first.length() - second.length());
		System.out.println(Arrays.toString(planets));
		
		Timer t = new Timer(1000, event -> System.out.println("The time is " + new Date()));
		t.start();
		
		JOptionPane.showMessageDialog(null, "Quit program");
		System.exit(0);
	}
	
}

結果:
在這裏插入圖片描述

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章