搜尋
首頁Javajava教程Java的Lambda表達式使用實例分析

Lambada 簡介

lambda 表達式 是Java 8新加入的新特性,它在Java中是引入了函數式程式設計這個概念。那什麼是函數式程式設計呢?

函數式程式設計:函數式程式設計是數學導向的抽象,將計算描述為一種表達式求值。

我們平常所說的物件導向程式設計屬於命令式程式設計,函數式程式設計和命令式程式設計的差別是:

  • 函數式程式設計關心資料的映射,命令式程式關係解決問題的步驟。

  • 函數式程式關係型別(代數結構)之間的關係,命令式程式設計關係解決問題的步驟。

函數式程式設計的本質:

#函數式程式設計中的函數指的不是電腦中的函數,而是數學中的函數,即自變數的映射。即:一個函數的值只取決於函數參數的值,不依賴其他狀態。

嚴格意義上的函數式程式設計意味著不使用可變的變量,賦值,循環和其他命令式控制結構進行程式設計。

函數式程式設計的好處:

函數式程式設計的好處是主要是不可變性帶來的。沒有可變的狀態,函數就是引用透明(Referential transparency)的和沒有副作用的(No Side Effect)。

上面這些都是一些基本的概念,但是我們平常可能接觸這些方面的東西比較少,所以一開始感覺函數式程式設計是很難得東西。

簡單的範例

Talk is cheap, show me the code!

先來一個最簡單的例子,可能也是介紹的最多的例子了。哈哈!

為按鈕新增監視器。

使用匿名內部類別的方式,進行新增。

submit.addActionListener(new ActionListener() {
	@Override
	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
	}
});

這種方式的缺點:使用了很多的模板程式碼,真正必要的程式碼,只是方法體內的程式碼。所以,Java 8 引入的 Lambda 表達式可以簡化這種程式碼(當然了,也是有限制的,不是所有的匿名內部類別都可以,這個後面會提到。)。

使用 Lambda 表達式 簡化程式碼

submit.addActionListener((e)->{
		JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
});

#Lambda 表達式是一個匿名方法,將行為像資料一樣傳遞。

說明

可以看出來,使用Lambda 表達式簡化後的程式碼表達變得更加清晰了,並且不用再寫入繁瑣的模板程式碼了。

當進一步簡化

參數括號和程式碼體的花括號也可以省略(只有一個參數時,可以省略圓括號,只有一行程式碼時,可以省略花括號)。

ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);

小結
當使用Lambda 表達式取代匿名內部類別建立物件時,Lambda 表達式的程式碼區塊將會取代實作抽象方法的方法體,Lambda 就相當於一個匿名方法。

Lambda 表達式的組成部分

lambda 表達式由三個部分組成:

  • 形參列表。形參清單允許省略形參類型。如果形參列表中只有一個參數,可以省略形參列表的圓括號。

  • 箭頭(->)。英文短線和大於號。

  • 程式碼區塊。如果程式碼區塊只有一句,可以省略花括號。如果只有一條 return 語句,可以省略 return,lambda表達式會自動傳回這條語句的值。

註:
之所以可以省略形參列表是因為編譯器可以進行類型推斷,例如:

List<Dog> dogs1 = new ArrayList<Dog>();

List<Dog> dogs2 = new ArrayList<>();

上面使用菱形語法,可以省略尖括號裡面的東西,這就是類型推斷的作用
但是類型推論也不是萬能的,不是所有的都可以推斷出來的,所以有時候,還是要顯示的添加形參類型,例如:

先不要管這個代碼的具體作用。

BinaryOperator b = (x, y)->x*y;
//上面这句代码无法通过编译,下面是报错信息:无法将 * 运算符作用于 java.lang.Object 类型。
The operator * is undefined for the argument type(s) java.lang.Object, java.lang.Object
//添加参数类型,正确的代码。
BinaryOperator<Integer> b = (x, y)->x*y;

所以,型別推斷不是萬能的,如果編譯器無法推斷,那就是我們的錯誤,不要過度依賴編譯器。有時候,顯示的新增參數類型,還是很必要的,當然了,這需要去多練習。

函數式介面

前面了解了,Lambda 表達式可以取代匿名內部類,進而達到簡化程式碼,表達清晰的目的。那麼使用 Lambda 表示式的前提是什麼呢? -- 函數式介面

Lambda 表達式的類型,也稱為 目標類型 (Target Type),它必須是函數式介面(Functional Interface)。所謂函數式接口,指的就是:只包含一個抽象方法的接口。 (可以包含多個預設方法,靜態方法,但必須只有一個抽象方法)。
附註:Java 8 專門提供了一個註解:@FunctionalInterface。用於標註某個接口是函數式接口,這樣編譯時就會檢查,如果該接口含有多個抽象方法,編譯器就會報錯。

上面使用 Lambda 表达式来为按钮添加了监视器,可以看出来,Lambda 表达式 代替了 new ActionListener()对象。

所以 Lambda 的表达式就是被当成一个对象。

例如:

ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);

从上面这个例子中可以看出来,Lambda 表达式实现的是匿名方法–因此它只能实现特定函数式接口中的唯一方法。
所以 Lambda 表达式有下面两种限制:

Lambda 表达式的目标类型必须是明确的函数式接口。 Lambda 表达式只能为函数式接口创建对象。Lambda只能实现一个方法,因此它只能为含有一个抽象方法的接口(函数式接口)创建对象。 介绍几个 Java 中重要的函数接口

Java的Lambda表達式使用實例分析

从这种表可以看出来,抽象方法的名字反而不是最重要的了,重要的是参数和返回值。 因为在写 Lambda 表达式的时候,也不要使用 抽象方法名了。

上面使用几个简单的例子来说明上面接口的应用:

测试代码

import java.text.ParseException;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

public class Test {
	public static void main(String[] args) throws ParseException {
		//Lambda 表达式中的构造器引用,用于简化代码。
		Creat<Dog> c = Dog::new;
		Dog dog = c.creat("小黑", 15);
		System.out.println(dog.toString());
		
		Predicate<String> predicate = (words)->{
			return words.length() > 20;
		};
		assert predicate.test("I love you yesterday and today!") : "长度小于20";
		assert !predicate.test("God bless you!") : "长度小于20";
		System.out.println("------------------------");
		
		Consumer<Dog> consumer = System.out::println;
		consumer.accept(dog);
		System.out.println("------------------------");

		Function<Dog, String> function = (dogObj)->{
			return dogObj.getName();
		};
		System.out.println(function.apply(dog));
		System.out.println("------------------------");
		
		Supplier<Dog> supplier = ()->{
			return new Dog("大黄", 4);
		};
		System.out.println(supplier.get());
		
		//一元操作符
		UnaryOperator<Boolean> unaryOperation = (flag)->{
			return !flag;
		};
		System.out.println(unaryOperation.apply(true));
		
		BinaryOperator<Integer> binaryOperator = (x, y)->x*y;
		int result = binaryOperator.apply(999, 9999);
		System.out.println(result);
	}
}

测试使用的实体类

public class Dog {
	private String name;
	private int age;
	
	public Dog(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Dog [name=" + name + ", age=" + age + "]";
	}
}

自定义函数式接口

@FunctionalInterface
public interface Creat<T> {
	public T creat(String name, int age);
}

运行截图就不放了,感兴趣的可以试一下。

说明
我这里直接使用 Lambda 创建了对象,然后调用了这个对象的方法(就是lambda 的代码块部分),真正使用的时候,都是直接传递 Lambda 表达式的,这种方法并不推荐,但是可以让我们很好的理解为什么? 可以看出来,Lambda 表达式的作用,最后还是需要调用 重写的抽象方法的,只不过使用表达更加清晰,简化了代码。

例如:

		List<Dog> dogs = new ArrayList<>();
		dogs.add(new Dog("大黄", 2));
		dogs.add(new Dog("小黑", 3));
		dogs.add(new Dog("小哈",1));
		//将行为像数据一样传递,使用集合的 forEach 方法来遍历集合,
		//参数可以是一个 Lambda 表达式。
		Consumer<? super Dog> con = (e)->{
			System.out.println(e);
		};
		dogs.forEach(con);
		System.out.println("--------------------------\n");
	
		//直接传递 Lambda 表达式,更加简洁
		dogs.forEach(e->System.out.println(e));
		System.out.println("--------------------------\n");

		//使用方法引用,进一步简化(可以看我的另一篇关于方法引用的博客)
		dogs.forEach(System.out::println);
		System.out.println("--------------------------\n");

		//使用 Lambda 对集合进行定制排序,按照年龄排序(从小到大)。
		dogs.sort((e1, e2)->e1.getAge()-e2.getAge());
		dogs.forEach(System.out::println);

可以看出来,通过使用 Lambda 表达式可以,极大的简化代码,更加方便的操作集合。值得一提的是:Lambda 表达式 和 Stream 的结合,可以拥有更加丰富的操作,这也是下一步学习的方向。

运行截图:

Java的Lambda表達式使用實例分析

以上是Java的Lambda表達式使用實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用