Java Lambda无返回值时报错:推理变量T#1边界不兼容咨询
问题分析与解决方案
问题描述
调用mkRunTime.e()时,带返回值的Lambda可以正常运行,但无返回值的Lambda会报类型不兼容错误。错误信息如下:
error: method e in interface mkRunTime<T#2> cannot be applied to given types; mkRunTime.e(() -> p.store(new FileWriter(fname), "Bookmarks") ); ^ required: mkRunTime<T#1> found: ()->p.stor[...]e2)" reason: inference variable T#1 has incompatible bounds lower bounds: Object lower bounds: void where T#1,T#2 are type-variables: T#1 extends Object declared in method <T#1>e(mkRunTime<T#1>) T#2 extends Object declared in interface mkRunTime
mkRunTime接口定义:
@FunctionalInterface public interface mkRunTime<T> { T execute() throws Exception; public static <T> T e(mkRunTime<T> runtime) { try { runtime.execute(); return null; } catch (Exception exception) { AlanActivity.me.get().ToastE(exception); throw new RuntimeException(exception); } } }
无错误的带返回值示例:
stream = mkRunTime.e(() -> new FileInputStream(filename));
临时可行的写法(手动返回null):
mkRunTime.e(() -> {p.store(new FileWriter(fname), "Bookmarks"); return null; });
核心原因
mkRunTime<T>的execute()方法要求返回T类型,但Java泛型的类型参数必须是对象类型,void不属于对象类型。当你传入无返回值的Lambda时,编译器试图推断T的类型,但同时得到Object(泛型默认下界)和void两个冲突的下界,因此报错。手动返回null时,编译器会推断T为Void(一个特殊的对象类型,代表无返回值),因此可以通过编译。
解决方案
1. 用单一接口兼容两种情况
不需要修改原mkRunTime接口,只需给静态方法e新增一个重载版本,专门处理无返回值场景:
@FunctionalInterface public interface mkRunTime<T> { T execute() throws Exception; // 原带返回值的方法 public static <T> T e(mkRunTime<T> runtime) { try { return runtime.execute(); } catch (Exception exception) { AlanActivity.me.get().ToastE(exception); throw new RuntimeException(exception); } } // 新增无返回值的重载方法 public static void e(mkRunTime<Void> runtime) { try { runtime.execute(); } catch (Exception exception) { AlanActivity.me.get().ToastE(exception); throw new RuntimeException(exception); } } }
这样调用无返回值Lambda时,编译器会自动推断为mkRunTime<Void>,无需手动写return null:
mkRunTime.e(() -> p.store(new FileWriter(fname), "Bookmarks"));
2. 定义专门的无返回值函数式接口
如果希望彻底分离两种场景,可以单独定义一个无返回值的接口:
@FunctionalInterface public interface mkRunTimeVoid { void execute() throws Exception; public static void e(mkRunTimeVoid runtime) { try { runtime.execute(); } catch (Exception exception) { AlanActivity.me.get().ToastE(exception); throw new RuntimeException(exception); } } }
调用方式:
mkRunTimeVoid.e(() -> p.store(new FileWriter(fname), "Bookmarks"));
内容的提问来源于stack exchange,提问作者Al Ro
相关产品推荐
相关产品推荐

