Java 8方法引用触发空指针异常,Lambda表达式却运行正常
Java 8方法引用引发NullPointerException,Lambda却正常的原因与解决办法
我之前踩过一模一样的坑!这个问题的核心是方法引用和Lambda在处理实例方法的目标对象时的执行时机差异。先把你提到的可复现代码补全(方便大家理解场景):
import java.util.function.Consumer; public class Main { public static void main(String[] args) { Foo foo = null; // 这一行直接抛出NullPointerException Consumer<String> methodRefConsumer = foo::print; // 这一行不会抛异常,直到调用accept()时才会触发NPE(如果foo还是null的话) Consumer<String> lambdaConsumer = s -> foo.print(s); } } class Foo { public void print(String content) { System.out.println(content); } }
为什么会出现这种差异?
- 方法引用:当你使用
foo::print这种实例方法引用时,JVM会在创建这个方法引用的瞬间就检查目标对象foo是否为null。因为实例方法必须绑定到一个具体的实例上才能执行,JVM不允许你创建一个指向null对象的实例方法引用,所以直接抛出NPE。 - Lambda表达式:Lambda本质上是一个延迟执行的匿名函数,它只是捕获了
foo的引用,并不会在创建时执行任何方法调用。只有当你调用lambdaConsumer.accept("xxx")的时候,才会尝试执行foo.print(s),这时候如果foo是null才会抛出NPE。
怎么解决?
根据你的业务场景,有两种常见处理方式:
确保目标对象非空再使用方法引用
如果你的逻辑里foo必须不为null才能工作,那就在创建方法引用之前做null校验,提前拦截问题:Foo foo = getFooInstance(); if (foo == null) { throw new IllegalArgumentException("Foo实例不能为null"); } Consumer<String> methodRefConsumer = foo::print;用Lambda替代方法引用,添加安全校验
如果foo可能为null,且你希望避免NPE或者做降级处理,用Lambda可以更灵活地控制逻辑:Consumer<String> safeConsumer = s -> { if (foo != null) { foo.print(s); } else { // 这里可以加降级逻辑,比如打印日志或者跳过执行 System.out.println("Foo实例为null,跳过打印"); } };
内容的提问来源于stack exchange,提问作者KnorpelSenf
相关产品推荐
相关产品推荐

