lambda 表達式是 Java8 的新特性,雖說都發布很久了,但是不到萬不得已是肯定不會研究這個的,現在就是那不得不學習的時候了。
本文主要說一下什么 lambda 表達式、Java 中為什么要有 lambda 表達式以及 lambda 表達式的應用。
在 Java 面向對象的思想中,我們知道函數是不能單獨存在的,函數一般會作為某個對象的功能封裝在對象之中,我們傳遞參數也不能傳遞一個函數。曾經 Java 也為此掙扎過,我們看下面這段代碼,創建一個線程,輸出一句話。
new Thread(new Runnable() { @Override public void run() { System.out.println("Hello World !"); } }).start();
有點基礎應該都知道這是匿名內部類,但是你知道的,真正有效的代碼就一行輸出語句。其余代碼基本沒用,我們可以反過來想一下,我們創建線程是為了執行某一個任務,也就是某一個方法,那我們為何不直接傳入一個方法呢?
按照這個思路,我們可以這樣寫偽代碼。
new Thread((某某任務)).start();
好了,現在問題就出現了,如何去形容這個任務,或者說在 Java 中如何表示呢?lambda 表達式應運而生。
一個函數,可能會有入參,函數要有函數體,於是就這樣定義了 lambda 表達式 “(參數1,參數2)-> { 函數體 } ” 。
但是吧,實際使用過程中,因為參數和函數體的不同,又有一些變種的寫法,一個 lambda 表達式可以有零個或多個參數,參數之間用逗號相隔。空括號代表參數為空。
lambda 表達式的主體可包含零條或多條語句,如果 lambda 表達式的主體只有一條語句,花括號 { } 可省略,否則必須包含在花括號 { } 中。
OK,到這里我們就可以重寫上面的線程了。
new Thread( () -> System.out.println("Hello World ") ).start();
說到這簡單回憶一下什么是 lambda 表達式,曾經 Java 中不能直接把函數做參數,為了能行,創造了 lambda 表達式,可以把 lambda 表達式理解為一個功能塊,只不過匿名罷了。
其實 lambda 的出現是為了和函數式編程相呼應,函數式編程,就是用函數為主體來編程,把函數當成是代碼的基本組成部分,就像變量一樣。官方說法叫第一等公民。
舉個例子說明一下函數式編程的特點。
計算如下表達式: (1 + 2) * 3 - 4 傳統的過程式編程,可能這樣寫(比較傻,為了演示效果): int a = 1 + 2; int b = a * 3; int c = b - 4; 函數式編程要求使用函數,我們可以把運算過程定義為不同的函數,然后寫成下面這樣: int result = subtract(multiply(add(1,2), 3), 4);
有點蒙,沒關系,先理解 lambda 表達式的使用再說,lambda 表達式最常用的莫過於替換 Runnable 接口實現線程任務,還有什么用處呢?
太難的不介紹,說一個比較簡單的,用於列表的迭代。
對一個列表的每一個元素進行操作,不使用 Lambda 表達式時如下:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); for (int element : numbers) { System.out.prinln(element); }
使用 Lambda 表達式:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.forEach(x -> System.out.println(x));
重點在操作上,輸入是 x ,然后對 x 進行輸出操作。就線程和列表迭代來說,為什么他們能接收 lambda 表達式作為參數呢?我們看看 forEach 方法的參數內部是什么。
* @since 1.8 */ @FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t);
是一個接口,而這個接口被定義為函數式接口,lambda 表達式可以替換功能接口,我們就來自定義一個函數式接口來演示一下。
定義一個函數式接口:
// 定義一個功能接口或叫函數式接口 @FunctionalInterface public interface WorkerInterface { // 該接口中只能有一個抽象方法 public void doSomeWork(); } public class WorkerInterfaceTest { public static void execute(WorkerInterface worker) { worker.doSomeWork(); } public static void main(String[] args) { // invoke doSomeWork using Annonymous class execute(new WorkerInterface() { @Override public void doSomeWork() { System.out.println("Worker invoked using Anonymous class"); } }); // invoke doSomeWork using Lambda expression execute(()->{System.out.println("Worker invoked using Lambda expression");}); } }
總結一下最開始提出的幾個問題,lambda 表達式可以理解為是一個匿名的函數,我們可以通過 lambda 表達式來代替功能接口(比方說 Runnable 接口)。函數式編程是一種編程模式,Java 為了支持它而定義了 lambda 。lambda 的應用主要在替代功能接口,列表迭代,還有一些對集合的操作上。
最后,能告訴我你現在使用 Lambda 表達式了嗎,都是用在什么地方呢 ?