https://u.nu/3whov
函数式接口是仅含一个抽象方法的接口,但可以指定 Object 定义的任何公有方法。
@FunctionalInterface
public interface IFuntionSum<T extends Number> {
T sum(List<T> numbers); // 抽象方法
}
以下也是一个函数式接口:
@FunctionalInterface
public interface IFunctionMulti<T extends Number> {
void multi(List<T> numbers); // 抽象方法
boolean equals(Object obj); // Object中的方法
}
@FunctionalInterface
public interface IFunctionMulti<T extends Number> extends IFuntionSum<T> {
void multi(List<T> numbers);
@Override
boolean equals(Object obj);
}
// IFunctionMulti 接口继承了 IFuntionSum 接口,此时 IFunctionMulti 包含了2个抽象方法
tip 1: 可以用 @FunctionalInterface 标识函数式接口,非强制要求,但有助于编译器及时检查接口是否满足函数式接口定义
tip 2: 在 Java 8 之前,接口的所有方法都是抽象方法,在 Java 8 中新增了接口的默认方法
包含单独表达式 :parameters -> an expression
list.forEach(item -> System.out.println(item));
包含代码块:parameters -> { expressions };
list.forEach(item -> {
int numA = item.getNumA();
int numB = item.getNumB();
System.out.println(numA + numB);
});
左侧指定 lambda 表达式需要的参数,右侧指定 lambda 方法体
每个 lambda 表达式背后必定有一个函数式接口,该表达式实现的是这个函数式接口内部的唯一抽象方法。
譬如以下 lambda 表达式:
list.forEach(item -> System.out.println(item));
我们看 ArrayList 中 foreach 方法:
@Override
public void forEach(Consumer<? super E> action) {
// 太长了,不看了~
}
其中 Consumer 是一个函数式接口:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t); // lambda 表达式 item -> System.out.println(item) 实现了该方法
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer 接口是 Java 8 中预先定义的函数式接口,java.util.function 包下都是些预定义的函数式接口 function 包下的部分接口使用了泛型,具有很强的通用性,在自定义函数式接口前,不妨去这个包下找找有没有能用的
public class LambdaDemo {
public static void main(String[] args) {
List<String> list = Arrays.asList("item1", "item2");
list.forEach(item -> System.out.println(item));
}
}
用 Java VisualVM 追踪代码运行过程中的堆内存,发现会生成以下实例:
生成的实例类名为 LambdaDemo$Lambda1,根据匿名内部类的命名规则可知,这是 LamddaDemo的 一个匿名内部类。(普通匿名内部类 和 lambda匿名内部类的命名规则见下文)。
// 有以下函数式接口
@FunctionalInterface
public interface IFuntionSum<T extends Number> {
T sum(List<T> numbers);
}
// 将一个lambda表达式赋值给函数式接口引用(类型须兼容)
IFuntionSum<Long> function = list -> {
Long sum = 0L;
for (Long item : list) {
sum += item;
}
return sum;
};
function.sum(Arrays.asList(1L, 2L)); // 执行结果为3L
在开发过程中,我们可以将 lambda 表达式等同于一个对象使用,对其声明、引用、传递。
外部类名$$Lambda$1 和 外部类名$$Lambda$2
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d);
}
IFunctionMod function = (n, d) -> (n % d) == 0 // 合理,n 和 d 的类型通过上下文推断
IFunctionMod function = (int n, int d) -> (n % d) == 0 // 合理,指定 n 和 d 的类型
IFunctionMod function = (int n, d) -> (n % d) == 0 // 不合理,须显示声明所有参数类型
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d) throw Exception;
}
IFunctionMod function = (n, d) -> {
if (d == 0) {
// IOException是EXception 的子类,通过类型转换,IOException 可转换为 Exception
throw new IOException("test");
}
return n % d == 0;
};
如果反一下,就不行了:
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d) throw IOException;
}
IFunctionMod function = (n, d) -> {
if (d == 0) {
// 父类不能通过自动类型转换转为子类,lambda 表达式抛出的异常类型与抽象方法抛出的异常类型不兼容
throw new Exception("test");
}
return n % d == 0;
};
可以引用已有方法构造 lambda 表达式,这里给一个例子,不做详细解释:
list.forEach(System.out::print)
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有