Lambda表达式是Java 8引入的一种简洁方式来表示匿名函数或行为,通常用于实现单方法接口(也称为函数式接口)。
Lambda 表达式的结构
Lambda表达式有三个主要部分:
- 参数列表:用括号
()
包围的参数列表。如果只有一个参数,并且类型可以从上下文中推断出来,则可以省略括号和参数类型。 - 箭头符号 (
->
):这是分隔参数列表和Lambda体的箭头符号。 - Lambda体:包含要执行的代码块。如果Lambda体只有一条语句,那么可以省略大括号
{}
和返回关键字return
;如果有多个语句,则需要使用大括号{}
包围起来,并且可能需要显式地使用return
。
示例
// 带有一个参数的Lambda表达式
Runnable r = () -> System.out.println("Hello, world!");
// 带有两个参数的Lambda表达式
BinaryOperator<Integer> adder = (a, b) -> a + b;
// 带有多个语句的Lambda表达式
Consumer<String> c = (String s) -> {
String result = s.toUpperCase();
System.out.println(result);
};
函数式接口
为了能够使用Lambda表达式,必须有一个函数式接口。函数式接口是指仅包含一个抽象方法的接口。Java 8 提供了 @FunctionalInterface
注解来标识这些接口,但这不是强制性的,只是一个提醒机制。以下是一些常见的函数式接口:
Runnable
:无参数,无返回值。Callable<V>
:无参数,带返回值。Consumer<T>
:接收一个参数,无返回值。Supplier<T>
:无参数,返回一个值。Function<T, R>
:接收一个参数,返回一个值。Predicate<T>
:接收一个参数,返回布尔值。BiFunction<T, U, R>
:接收两个参数,返回一个值。BinaryOperator<T>
:接收两个相同类型的参数,返回相同类型的值(如上面的adder
)。
创建自定义函数式接口
你可以创建自己的函数式接口,只要确保接口中只有一个抽象方法即可。例如:
@FunctionalInterface
interface MyFunction<T, R> {
R apply(T t);
}
然后你可以使用Lambda表达式来实现这个接口:
MyFunction<String, Integer> stringToInt = Integer::parseInt;
Integer number = stringToInt.apply("123"); // 转换字符串 "123" 为整数 123
方法引用
当Lambda表达式的内容只是调用一个已有方法时,可以进一步简化为方法引用。方法引用可以看作是Lambda表达式的简写形式。它们分为三类:
- 静态方法引用:
ClassName::staticMethod
- 实例方法引用:
instance::method
- 构造器引用:
ClassName::new
示例
// 静态方法引用
Comparator<String> comp = String::compareToIgnoreCase;
// 实例方法引用
List<String> strings = Arrays.asList("hello", "world");
strings.sort(String::compareTo);
// 构造器引用
Button button = Button::new;
总结
Lambda表达式提供了一种更简洁的方式来表示匿名函数,特别是当你只需要实现一个方法时。它们通常与函数式接口一起使用,并且可以极大地简化代码,尤其是在集合操作、事件处理和并发编程等场景下。方法引用则是对特定情况下的Lambda表达式的进一步简化。