Maison > Java > javaDidacticiel > Analyse d'exemple d'utilisation d'expression Java Lambda

Analyse d'exemple d'utilisation d'expression Java Lambda

WBOY
Libérer: 2023-04-18 16:01:03
avant
792 Les gens l'ont consulté

Lambada Introduction

L'expression lambda est une nouvelle fonctionnalité ajoutée à Java 8. Elle introduit le concept de programmation fonctionnelle en Java. Alors, qu’est-ce que la programmation fonctionnelle ?

Programmation fonctionnelle : La programmation fonctionnelle est une abstraction orientée mathématiques qui décrit le calcul comme une évaluation d'expression.

Ce que nous appelons habituellement la programmation orientée objet appartient à la programmation impérative. La différence entre la programmation fonctionnelle et la programmation impérative est la suivante :

  • La programmation fonctionnelle se soucie du mappage des données, tandis que la programmation impérative concerne les étapes à résoudre. problèmes.

  • Relations entre les types de relations de programmation fonctionnelle (structures algébriques), les relations de programmation impératives et les étapes pour résoudre les problèmes.

L'essence de la programmation fonctionnelle :

La fonction en programmation fonctionnelle ne fait pas référence à la fonction dans l'ordinateur, mais à la fonction en mathématiques, c'est-à-dire la cartographie de variables indépendantes. Autrement dit : la valeur d'une fonction dépend uniquement de la valeur du paramètre de la fonction et ne dépend pas des autres états.

La programmation fonctionnelle au sens strict signifie programmer sans utiliser de variables mutables, d'affectations, de boucles et d'autres structures de contrôle impératives.

Avantages de la programmation fonctionnelle :

Les avantages de la programmation fonctionnelle proviennent principalement de l'immuabilité. Sans état mutable, les fonctions sont référentiellement transparentes et n'ont aucun effet secondaire.

Ce qui précède sont quelques concepts de base, mais nous avons peut-être moins de contact avec ces aspects, donc au début, je pense que la programmation fonctionnelle est une chose rare.

Exemple simple

Parler ne coûte pas cher, montre-moi le code !

Prenons d'abord l'exemple le plus simple, et il peut aussi être l'exemple le plus présenté. Ha ha !

Ajouter un moniteur au bouton.

Utilisez des classes internes anonymes pour ajouter.

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

Inconvénients de cette méthode : beaucoup de code de modèle est utilisé, et le seul code vraiment nécessaire est le code dans le corps de la méthode. Par conséquent, l'expression Lambda introduite dans Java 8 peut simplifier ce type de code (bien sûr, il y a des limites. Toutes les classes internes anonymes ne peuvent pas être utilisées, ce qui sera mentionné plus tard.).

Utilisez des expressions Lambda pour simplifier le code

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

L'expression Lambda est une méthode anonyme qui transmet des comportements tels que des données.

Explication

On peut voir que l'expression de code simplifiée utilisant des expressions Lambda devient plus claire et qu'il n'est plus nécessaire d'écrire du code de modèle fastidieux.

Encore plus simplifié

Les parenthèses de paramètres et les accolades du corps du code peuvent également être omis (Lorsqu'il n'y a qu'un seul paramètre, les parenthèses peuvent être omises, et lorsqu'il n'y a qu'une seule ligne de code, le bouclé les accolades peuvent être omises).

ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
Copier après la connexion
Copier après la connexion
Copier après la connexion

Résumé
Lorsque vous utilisez une expression Lambda au lieu d'une classe interne anonyme pour créer un objet, le bloc de code de l'expression Lambda remplacera le corps de la méthode qui implémente la méthode abstraite, et Lambda équivaut à une méthode anonyme.

Composants de l'expression Lambda

L'expression lambda se compose de trois parties :

  • liste des paramètres formels. La liste des paramètres formels permet d'omettre les types de paramètres formels. S'il n'y a qu'un seul paramètre dans la liste des paramètres, les parenthèses dans la liste des paramètres peuvent être omises.

  • Flèche (->). Tiret anglais et signe supérieur à.

  • Blocs de code. Si le bloc de code ne contient qu’une seule phrase, vous pouvez omettre les accolades. S'il n'y a qu'une seule instruction return, vous pouvez omettre return et l'expression lambda renverra automatiquement la valeur de cette instruction. return 语句,可以省略 return,lambda表达式会自动返回这条语句的值。

注:
之所以可以省略形参列表是因为 编译器 可以进行类型推断,例如:

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

List<Dog> dogs2 = new ArrayList<>();
Copier après la connexion

上面使用 菱形语法,可以省略尖括号里面的东西,这就是类型推断的作用
但是类型推断也不是万能的,不是所有的都可以推断出来的,所以有时候,还是要显示的添加形参类型,例如:

先不要管这个代码的具体作用。

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

所以,类型推断不是万能的,如果编译器无法推断,那就是我们的错误,不要过度依赖编译器。有时候,显示的添加参数类型,还是很必要的,当然了,这需要去多练习。

函数式接口

前面了解了,Lambda 表达式可以代替匿名内部类,进而达到简化代码,表达清晰的目的。那么使用 Lambda 表示式的前提是什么呢?-- 函数式接口

Lambda 表达式的类型,也被称为 目标类型 (Target Type),它必须是一个函数式接口(Functional Interface)。所谓函数式接口,指的就是:只包含一个抽象方法的接口。(可以包含多个默认方法,静态方法,但必须只有一个抽象方法)。
注:Java 8 专门提供了一个注解:@FunctionalInterface

🎜🎜🎜Remarque : 🎜🎜La liste des paramètres formels peut être omise parce que le compilateur peut effectuer une inférence de type, par exemple : 🎜
ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
Copier après la connexion
Copier après la connexion
Copier après la connexion
🎜La syntaxe en diamant est utilisée ci-dessus, et les éléments entre les crochets angulaires peuvent être omis. C'est le rôle de l'inférence de type 🎜. 🎜Mais l'inférence de type n'est pas omnipotente, tout ne peut pas être déduit, donc parfois, il est encore nécessaire d'ajouter 🎜des types de paramètres formels 🎜 explicitement, par exemple : 🎜🎜Ne vous inquiétez pas de la fonction spécifique de ce code pour l'instant. 🎜
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);
	}
}
Copier après la connexion
Copier après la connexion
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 + "]";
	}
}
Copier après la connexion
Copier après la connexion
🎜🎜Donc, l'inférence de type n'est pas omnipotente. Si le compilateur ne peut pas la déduire, c'est notre erreur. Ne vous fiez pas trop au compilateur. Parfois, il est encore nécessaire d’ajouter explicitement des types de paramètres. Bien entendu, cela nécessite plus de pratique. 🎜🎜🎜Interface fonctionnelle🎜🎜Comme nous l'avons appris plus tôt, les expressions Lambda peuvent remplacer les classes internes anonymes pour simplifier le code et s'exprimer clairement. Alors, quelles sont les conditions préalables à l’utilisation des expressions Lambda ? -- 🎜Interface fonctionnelle🎜🎜🎜Le type d'expression Lambda, également appelé Type cible, doit être une interface fonctionnelle. L'interface dite fonctionnelle fait référence à : 🎜Une interface qui ne contient qu'une seule méthode abstraite. 🎜(Peut contenir plusieurs méthodes par défaut, méthodes statiques, mais il ne doit y avoir qu'une seule méthode abstraite). 🎜Remarque : Java 8 fournit une annotation spéciale : @FunctionalInterface. Utilisé pour marquer une interface comme interface fonctionnelle, afin qu'elle soit vérifiée lors de la compilation. Si l'interface contient plusieurs méthodes abstraites, le compilateur signalera une erreur. 🎜

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

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

例如:

ActionListener listener = e->JOptionPane.showMessageDialog(null, "点击了确定按钮", "确定", JOptionPane.INFORMATION_MESSAGE);
Copier après la connexion
Copier après la connexion
Copier après la connexion

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

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

Analyse d'exemple d'utilisation d'expression 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);
	}
}
Copier après la connexion
Copier après la connexion

测试使用的实体类

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 + "]";
	}
}
Copier après la connexion
Copier après la connexion

自定义函数式接口

@FunctionalInterface
public interface Creat<T> {
	public T creat(String name, int age);
}
Copier après la connexion

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

说明
我这里直接使用 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);
Copier après la connexion

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

运行截图:

Analyse d'exemple d'utilisation d'expression Java Lambda

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal