lambda表达式

本文深入探讨了Java 8中的Lambda表达式和方法引用,通过对比不同方式的代码实现,展示了Lambda表达式如何简化代码并提高编程效率。同时,详细解析了Lambda表达式的语法特点及其在实际应用中的优势。

举个栗子

我们在讨论lambda表达式之前先看个例子。

现在有个类Person,并且我们创建了数组,要求时根据这些人的年龄排序,我们可以用Arrays类的sort方法进行排序,但是要求需要传入一个比较器,而比较器的具体内容是要我们自己实现的。现在我们可以写成这样:

import java.util.Arrays;
import java.util.Comparator;

public class Test {
	public static void main(String[] args) {
		Person[] persons = {new Person(20, "张三"), new Person(18, "李四"), new Person(26, "王五"), new Person(30, "赵六")};
		Arrays.sort(persons, new MyComparator());
		for (Person person : persons) 
			System.out.println(person.toString());
	}
}

class MyComparator implements Comparator<Person> {
	@Override
	public int compare(Person o1, Person o2) {
		return o1.getAge() - o2.getAge();
	}
	
}

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

	public int getAge() {
		return age;
	}

	public String getName() {
		return name;
	}
	
	public String toString() {
		return String.format("%s %d", this.name, this.age);
	}
}

因为Comparator是个接口,所有我们要完成一个实现这个接口的类MyComparator。这样写虽然可以完成,但是有点臃肿,当比较方法不一样了还要写个实现Comparator接口的类,所以我们可以改成用匿名函数的写法:

	public static void main(String[] args) {
		Person[] persons = {new Person(20, "张三"), new Person(18, "李四"), new Person(26, "王五"), new Person(30, "赵六")};
		Arrays.sort(persons, new Comparator<Person>() {
			@Override
			public int compare(Person o1, Person o2) {
				return o1.getAge() - o2.getAge();
			}
		});
		for (Person person : persons) 
			System.out.println(person.toString());
	}

这样写我们就不需要再完成一个实现Comparator接口的类了,减少了代码量,也显得优雅。但是现在再看一下代码,其实起到作用的只有return o1.getAge() - o2.getAge();,那能不能再精简一下能,这时候就需要lambda表达式了。

lambda表达式

什么是lambda表达式

什么是lambda表达式?lambda表达式就是一种匿名函数,我们先看一下上面的例子用lambda表达式怎么写:

		Person[] persons = {new Person(20, "张三"), new Person(18, "李四"), new Person(26, "王五"), new Person(30, "赵六")};
		Arrays.sort(persons, (Person o1, Person o2) -> {return o1.getAge() - o2.getAge();});
		for (Person person : persons) 
			System.out.println(person.toString());

之前传入的比较器现在被(Person o1, Person o2) -> {return o1.getAge() - o2.getAge();}代替。我们先看一下为什么原本的用匿名类传参可以写成现在这种样子。

在java8中的新特性中,如果接口只有一个抽象接口则这个接口叫做函数式接口(我们创建函数式接口时可以用@FunctionalInterface进行注解,同时java中也提供了一些常用的函数式接口,如:RunnableSupplier<T>等),就可以使用lambda表达式,而Comparator接口的源码中只有compare是抽象接口,因此Comparator接口就是函数式接口,所以一个比较器我们还可以写成这样:

Comparator<Person> comparator = (Person o1, Person o2) -> {return o1.getAge() - o2.getAge();};

代码可以进行根据上下文进行判断,用lambda表达式写成的匿名函数就是接口中唯一一个抽象接口的实现,同时再创建一个实现函数式接口的具体类。

lambda表达式的语法

在上面的示例中,Comparator接口中compare是抽象接口已经定义了是两个参数,所以在lambda表达式中是(Person o1, Person o2),如果只有一个参数可以写成(Person o1),若没有参数必须有括号()

(Person o1) -> {return o1.getAge();};
() -> {return 1;};

在函数式接口中的抽象方法中我们已经定义了入参的类型,因此可以吧声明类型去掉:

Arrays.sort(persons, (o1, o2) -> {return o1.getAge() - o2.getAge();});

如果只有一个入参,把声明类型去掉后还可以吧括号去掉:

o1 -> {return o1.getAge();};

说完入参我们再来看看代码块。若只有一个return语句,我们可以把return{}都去掉:

Arrays.sort(persons, (o1, o2) -> o1.getAge() - o2.getAge());

lambda代码中的作用域

lambda代码块中的引用的外部变量必须是final修饰的常量。因为lambda代码有可能是多线程或者延时执行,如果引用了外部普通变量,当lambda代码中使用此变量时,此时变量的值已经改变或者,这样可能导致严重问题。

在lambda代码中变量名称不能与父级方法中的变量相同。

方法引用

在了解方法引用之前,来先看个例子:

public class Test1 {
	public static void main(String[] args) {
		System.out.println(test(-10, x -> {
			if (x < 0) 
				return 0 - x;
			else 
				return x;
		}));
	}
	
	private static int test(int x, MyFunctionInterface functionalInterface) {
		return functionalInterface.operate(x);
	}
}

@FunctionalInterface
interface MyFunctionInterface {
	int operate(int x);
}

这段代码,创建了一个函数式接口MyFunctionInterface和一个静态方法test,在静态方法test中调用函数式接口中的operate方法处理入参,最后我们用lambda表达式实现了取绝对值的功能。不过在java的Math中也有取绝对值的方法abs,我们可以改写成:

System.out.println(test(-10, x -> Math.abs(x)));

这时候可以用到lambda中的方法引用:

System.out.println(test(-10, Math::abs));

从上面可以看出,其实就是把Math的abs方法作为函数式接口抽象接口的具体实现。

上面的例子中引用的是Math类的静态方法abs,方法引用主要分三种:

  1. Class::staticMethod
  2. object::instanceMethod
  3. Class::instanceMethod

对于前两种引用很好理解,都可以等价于x -> Class.staticMethod(x)或者x -> object.instanceMethod(x),而第三种引用等价于(x, y) -> x.instanceMethod(y)

### Lambda表达式的使用方法和示例 Lambda 表达式是一种简洁的语法形式,用于定义匿名函数或委托。它能够以非常紧凑的方式表示一段可执行逻辑,并且在多种编程语言中得到了广泛应用,例如 Java、C# 和 C++。 #### 基本语法与用法 Lambda 表达式的基本结构通常包括参数列表、箭头符号 `->` 或 `=>` 以及函数体。以下是一些典型的 Lambda 表达式示例: ```java // 无参Lambda表达式 Runnable runnable = () -> { System.out.println("Hello, World!"); }; ``` ```java // 有参Lambda表达式 Function<Integer, String> function = (num) -> "数字是:" + num; ``` ```java // 单行Lambda表达式 Predicate<String> predicate = (s) -> s.length() > 5; ``` 这些示例展示了如何通过 Lambda 表达式简化代码逻辑,使其更加直观和易于维护[^2]。 #### 在实际场景中的应用 Lambda 表达式的一个常见用途是作为参数传递给需要函数式接口的方法,例如在集合操作中进行过滤或映射: ```java public class Demo01Lambda { public static void method(int num, Calcable lambda) { System.out.println(lambda.cal(num)); } public static void main(String[] args) { method(-1314, n -> Math.abs(n)); // 使用Lambda表达式计算绝对值 [^1] } } ``` 在此示例中,Lambda 表达式 `n -> Math.abs(n)` 被用来替代一个单独定义的方法,从而减少了冗余代码并提高了可读性。 #### 与委托结合使用(C#) 在 C# 中,Lambda 表达式可以用来快速定义委托,而无需显式声明方法: ```csharp Func<int, int> square2 = x => x * x; // 使用Lambda表达式定义平方函数 Console.WriteLine(square2(5)); // 输出结果为25 [^3] ``` 这种写法不仅简化了代码结构,还使得逻辑意图更为清晰。 #### 方法引用与参数匹配 当 Lambda 表达式仅调用某个已存在的方法时,可以直接使用方法引用来进一步简化代码: ```java Function<String, Integer> func = String::length; // 正确:将字符串长度方法作为函数引用 ``` 此处的 `String::length` 是对 `String` 类中 `length()` 方法的一种直接引用,它等价于 `(s) -> s.length()`。这种方法引用方式要求被引用方法的参数列表必须与目标函数式接口的抽象方法参数相匹配[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值