Lambda表达式必须赋值给函数式接口,底层通过invokedynamic指令动态绑定,不生成.class文件;需掌握Consumer、Supplier、Predicate、Function四大接口及Stream链式操作与陷阱。

直击大厂面试,Lambda 表达式不能只写对,得讲清“为什么这么写”和“底层发生了什么”。面试官真正想考的,是你的技术纵深——比如看到 list.forEach(System.out::println),你能否立刻反应出这背后是函数式接口 + invokedynamic 指令,而不是“语法糖=匿名内部类”这种过时理解。
紧扣函数式接口,别让Lambda“裸奔”
Lambda 表达式本身没有类型,它必须赋值给一个函数式接口(只有一个抽象方法的接口)。这是硬性前提,也是面试第一道门槛。
- 必须能准确说出
@FunctionalInterface的作用:编译期校验,不是运行时必需,但加了能防误改 - 能列举四大核心函数式接口:
Consumer<t></t>(消费,无返回)、Supplier<t></t>(供给,有返回无参数)、Predicate<t></t>(判断,返回 boolean)、Function<t></t>(转换,输入 T 输出 R) - 遇到自定义接口时,要主动检查抽象方法数量;重写
Object方法(如toString())不算在内
说清底层机制,避开“语法糖”误区
面试官常问:“Lambda 编译后生成匿名内部类吗?”答“是”就掉坑里了。Java 8 后,Lambda 通过 invokedynamic 指令在运行时动态绑定,不生成 .class 文件,也不持有外部类引用(避免内存泄漏)。
- 验证方式:用
javap -c反编译,看不到 Lambda 对应的类;但能看到invokedynamic调用点 - 对比 Runnable:匿名内部类会生成
XXX$1.class,Lambda 不会 - 延伸一点:Lambda 中的
this指向的是外层对象,不是 Lambda 自身(它根本没实例)
结合 Stream 写出有业务感的代码
光会 forEach 不够,大厂爱考真实场景下的链式调用与错误处理。
立即学习“Java免费学习笔记(深入)”;
- 电商订单示例:从订单列表中筛选“未支付+金额>100”,按创建时间倒序取前5条
orders.stream()<br> .filter(o -> "UNPAID".equals(o.getStatus()) && o.getAmount() > 100)<br> .sorted(Comparator.comparing(Order::getCreateTime).reversed())<br> .limit(5)<br> .collect(Collectors.toList());
- 注意点:
filter和map是惰性求值,collect或forEach才触发执行;并行流慎用,非线程安全操作易出错
警惕高频陷阱题,提前堵住漏洞
这些不是偏题,而是筛选“真懂”的关键信号。
-
受检异常问题:Lambda 体里抛
IOException会编译失败,因为Consumer等接口方法不声明 throws;需包装成非受检异常或用自定义函数式接口 - 变量捕获限制:只能访问局部变量的“有效 final”版本(即未被重新赋值),否则编译报错
-
串行 vs 并行流:
stream().parallel()不保证顺序,forEach无序,要用forEachOrdered


















