Lambda
Lambda 是一个匿名函数,可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到了提升。
- Lambda 表达式的语法显然比匿名内部类更简洁:
// 匿名内部类
new Thread (new Runnable() {
@Override
public void run() {
System.out.println("One man's constant is another man's variable.");
}
});
// Lambda 表达式
new Thread(()-> System.out.println("One man's constant is another man's variable.")).start();
Lambda 表达式的其他形式:
- Lambda 需要一个参数,但无返回值
// 接口需要一个形参
Consumer<String> consumer = (String s) -> {
System.out.println(s);
};
consumer.accept("One man's constant is another man's variable.");
- 类型推断,可省略形参的数据类型
// 省略参数类型声明 - String
Consumer<String> consumer = (s) -> {
System.out.println(s);
};
consumer.accept("One man's constant is another man's variable.");
- 若 Lambda 表达式只需一个参数且仅有一条语句时,
()、{}、return(若有返回值) 可省略
// 接口仅需一个参数,可省略小括号
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("One man's constant is another man's variable.");
函数式编程接口
函数式接口:只包含一个抽象方法的接口。
简单的说,Lambda 表达式就是一个函数式接口的实例。
我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
Java 内置四大核心函数式接口
| 函数式接口 | 参数类型 | 返回类型 | 用途 |
|---|---|---|---|
| 消费型接口:Consumer | T | void | 对类型为 T 的对象应用操作,包含方法: void accept(T t) |
| 供给型接口:Supplier | 空 | T | 返回类型为 T 的对象,包含方法: T get() |
| 函数型接口:Function<T, R> | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法: R apply(T t) |
| 断定型接口:Predicate | T | boolean | 确定类型为T的对象是否满足某约束,并返回 boolean 值。包含方法: boolean test(T t) |
测试用例:
@Test
public void demo() {
List<String> list = Arrays.asList("北京", "南京", "天津");
List<String> filtered = filterString(list, s -> s.contains("京"));
System.out.println(filtered);
}
public List<String> filterString(List<String> list, Predicate<String> pre) {
// 过滤后的集合
ArrayList<String> filteredList = new ArrayList<>();
for (String s : list) {
if (pre.test(s)) {
filteredList.add(s);
}
}
return filterList;
}
方法引用
方法引用可以看做是 Lambda 表达式深层次的表达。
换句话说,方法引用就是 Lambda 表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是 Lambda 表达式的一个语法糖。
如果 函数式接口的实现恰好仅通过一个方法实现,则可以使用方法引用替换函数式接口。
主要分为以下三种情况
- 对象 :: 实例方法
@Test
public void demo() {
Assassin w = new Assassin("伍六柒", 16);
// 调用 Assassin 对象 w 的 getName() 方法
Supplier<String> sup = w::getName;
System.out.println(sup.get());
}
- 类 :: 静态方法
@Test
public void demo() {
// 调用 Math 的 round() 方法
Function<Double, Long> func2 = Math::round;
System.out.println(func2.apply(12.6));
}
- 类 :: 实例方法
@Test
public void demo() {
BiPredicate<String, String> pre = String::equals;
// 调用 String 的 equals() 方法
System.out.println(pre.test("and", "or"));
}
注意:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
构造器引用
格式: ClassName::new
// Lambda 表达式
Function<Integer, MyClass> lambda = (n)->new MyClass(n);
// 构造器引用
Function<Integer, MyClass> constructor = MyClass::new;
数组引用
格式: type[] :: new
// Lambda 表达式
Function<Integer, Integer[]> lambda = (n)->new Integer[n];
// 数组引用
Function<Integer, Integer[]> arr = (n)->Integer[]::new;