幾個例子輕鬆理解Lambda表達式

Lambda表達式介紹

Lambda表達式是一個匿名函數(方法)代碼塊,可以作爲表達式、方法參數和方法返回值。

Lambda表達式標準語法形式如下:

(參數列表) -> {
    //Lambda表達式
}

Lambda表達式實現的接口不是普通的接口,稱爲函數式接口,這種接口只能有一個方法。如果接口中聲明多個抽象方法,那麼Lambda表達式會發生編譯錯誤。

@FunctionalInterface 聲明函數式接口註解

在接口前使用@FunctionalInterface註解修飾,那麼試圖增加一個抽象方法時會發生編譯錯誤。但是可以添加默認方法和靜態方法。

1、Lambda表達式簡化形式

1)省略參數類型

Lambda表達式可以根據上下文環境推斷出參數類型。

public class HelloWorld {

	public static void main(String[] args) {

		int n1 = 10;
		int n2 = 5;

		// 實現加法計算Calculable對象
		Calculable f1 = calculate('+');
		// 實現減法計算Calculable對象
		Calculable f2 = calculate('-');

		// 調用calculateInt方法進行加法計算
		System.out.printf("%d + %d = %d \n", n1, n2, f1.calculateInt(n1, n2));
		// 調用calculateInt方法進行減法計算
		System.out.printf("%d - %d = %d \n", n1, n2, f2.calculateInt(n1, n2));
	}

	/**
	 * 通過操作符,進行計算 
	 * @param opr 操作符
	 * @return 實現Calculable接口對象
	 */
	public static Calculable calculate(char opr) {

		Calculable result;

		if (opr == '+') {
			// Lambda表達式實現Calculable接口
			result = (a, b) -> {
				return a + b;
			};
		} else {
			// Lambda表達式實現Calculable接口
			result = (a, b) -> {
				return a - b;
			};
		}

		return result;
	}
}

2)省略參數小括號

Lambda表達式有一個參數時,可以省略參數小括號。

public class HelloWorld {

	public static void main(String[] args) {

		int n1 = 10;

		// 實現二次方計算Calculable對象
		Calculable f1 = calculate(2);
		// 實現三次方計算Calculable對象
		Calculable f2 = calculate(3);

		// 調用calculateInt方法進行加法計算
		System.out.printf("%d二次方 = %d \n", n1, f1.calculateInt(n1));
		// 調用calculateInt方法進行減法計算
		System.out.printf("%d三次方 = %d \n", n1, f2.calculateInt(n1));
	}

	/**
	 * 通過冪計算
	 * @param power 冪
	 * @return 實現Calculable接口對象
	 */
	public static Calculable calculate(int power) {

		Calculable result;

		if (power == 2) {
			// Lambda表達式實現Calculable接口
			result = (int a) -> {	//標準形式
				return a * a;
			};
		} else {
			// Lambda表達式實現Calculable接口
			result = a -> {		//省略形式
				return  a * a * a;
			}; 
		}
		return result;
	}
}

3)省略return和大括號

如果Lambda表達式體中只有一條語句,可以省略return和大括號

result = a -> a * a * a;

2、作爲參數使用Lambda表達式

作爲參數傳遞給方法是Lambda表達式的一個常見的用法。

public class HelloWorld {

	public static void main(String[] args) {

		int n1 = 10;
		int n2 = 5;

		// 打印計算結果加法計算結果
		display((a, b) -> {
			return a + b;
		}, n1, n2);   //1

		// 打印計算結果減法計算結果
		display((a, b) -> a - b, n1, n2); ///2

	}

	/**
	 * 打印計算結果
	 * 
	 * @param calc Lambda表達式
	 * @param n1 操作數1
	 * @param n2 操作數2
	 */
	public static void display(Calculable calc, int n1, int n2) {//3
		System.out.println(calc.calculateInt(n1, n2));
	}
}

代碼中第3行定義display打印計算方法,其中參數clac是Calculable,這個參數既可以接收實現Calculable接口的對象,也可以接收Lambda表達式,因爲Calculable是函數式接口。

//可計算接口 
@FunctionalInterface
public interface Calculable {
	// 計算兩個int數值
	int calculateInt(int a, int b);
}

3、訪問變量

Lambda表達式可以訪問所在外層作用域內定義的變量,包括成員變量和局部變量。

public class LambdaDemo {
	// 實例成員變量
	private int value = 10;
	// 靜態成員變量
	private static int staticValue = 5;

	// 靜態方法,進行加法運算 靜態方法中不可以訪問實例成員變量,也不能訪問實例成員方法
	public static Calculable add() {

		Calculable result = (int a, int b) -> {
			// 訪問靜態成員變量,不能訪問實例成員變量
			staticValue++;
			int c = a + b + staticValue; // this.value;
			return c;
		};

		return result;
	}

	// 實例方法,進行減法運算   實例方法中可以訪問實例成員變量,也可以訪問實例成員方法
    // 當訪問實例成員變量或者成員實例方法可以使用this,在不與局部變量發生衝突的情況下可以省略this
	public Calculable sub() {

		Calculable result = (int a, int b) -> {
			// 訪問靜態成員變量和實例成員變量
			staticValue++;
			this.value++;
			int c = a - b - staticValue - this.value;
			return c;
		};
		return result;
	}
}

 捕獲局部變量

對於成員變量的訪問,Lambda表達式和普通方法沒有區別,但是在訪問外層局部變量時會發生“捕獲變量”情況。在Lambda表達式中捕獲變量時,會將變量當成final的,在Lambda表達式中不能修改那些捕獲的變量。

// 靜態方法,進行加法運算
	public static Calculable add() {
		//局部變量
		int localValue = 20;

		Calculable result = (int a, int b) -> {
			// localValue++; //編譯錯誤
			int c = a + b + localValue;
			return c;
		};
		return result;
	}

4、方法引用

java8之後增加了“::”運算符,用於方法引用,不是調用方法。

方法引用分爲靜態方法的引用和實例方法的引用。

類型名::靜態方法
實例名::實例方法

被引用方法的參數列表和返回值類型必須和函數式接口方法參數列表和方法返回值類型一致。

public class LambdaDemo {
	
	// 靜態方法,進行加法運算
	// 參數列表要與函數式接口方法calculateInt(int a, int b)兼容
	public static int add(int a, int b) {
		return a + b;
	}

	// 實例方法,進行減法運算
	// 參數列表要與函數式接口方法calculateInt(int a, int b)兼容
	public int sub(int a, int b) {
		return a - b;
	}
}

public class HelloWorld {

	public static void main(String[] args) {

		int n1 = 10;
		int n2 = 5;

		// 打印計算結果加法計算結果
		display(LambdaDemo::add, n1, n2); //display纔是真正調用方法
		
		LambdaDemo d = new LambdaDemo();
		// 打印計算結果減法計算結果
		display(d::sub, n1, n2);

	}

	/**
	 * 打印計算結果
	 * @param calc Lambda表達式
	 * @param n1  操作數1
	 * @param n2 操作數2
	 */
	public static void display(Calculable calc, int n1, int n2) {
		System.out.println(calc.calculateInt(n1, n2));
	}
}

來源:關東昇 《Java從小白到大牛》

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