为何存在潜在类型不匹配的Java代码可正常运行?
为什么
forEach中调用返回Future的submit方法能编译通过? 问题描述
一段Java代码中,forEach(i -> s.submit(() -> waitTillFinished(cb)))这行看似存在类型不匹配:s.submit()返回Future<?>,但forEach()接收的Consumer接口方法返回类型为void。但这段代码却能正常运行,尝试用自定义函数式接口替代Consumer时却编译失败,想了解其中原因。
完整代码如下:
public class Boat { private void waitTillFinished(CyclicBarrier c) { try { c.await(); System.out.print("W"); } catch (Exception e) { } } public void row(ExecutorService s) { var cb = new CyclicBarrier(5); IntStream.iterate(1, i -> i + 1).limit(12).forEach(i -> s.submit(() -> waitTillFinished(cb))); } public static void main(String[] oars) { ExecutorService service = null; try { service = Executors.newCachedThreadPool(); new Boat().row(service); } finally { service.shutdown(); } } }
原因解析
1. Consumer接口允许Lambda忽略返回值
Java语言规范明确规定:当Lambda表达式的目标函数式接口的抽象方法返回void时,Lambda体可以是任意表达式语句——无论该表达式是否有返回值,其返回值都会被直接丢弃,不会引发类型不匹配。
在这段代码中,forEach接收的Consumer<Integer>接口的accept方法返回void,因此Lambda表达式i -> s.submit(...)是完全合法的:这里把s.submit(...)(返回Future<?>)当作一个语句执行,直接忽略它的返回值,完全符合Consumer的方法签名要求。
2. 自定义接口编译失败的常见原因
你替换Consumer后编译失败,通常是以下情况之一:
- 自定义接口的抽象方法返回非
void类型:如果接口方法要求返回某个类型(比如Future<?>或Object),但Lambda的写法未匹配返回值(不过submit本身返回Future,这种情况较少见); - 方法参数不匹配:
Consumer的accept方法参数是Integer(适配IntStream的int类型),如果自定义接口方法参数类型不是int或Integer,会导致参数不匹配; - 自定义接口不是函数式接口:接口中存在多个抽象方法,或者未符合函数式接口的定义(仅含一个抽象方法),Java无法将Lambda适配到该接口;
- 显式类型转换错误:替换时未正确指定Lambda的目标类型,导致编译器无法推断接口类型。
举个例子,若自定义一个和Consumer等价的接口,写法正确的话是可以编译的:
@FunctionalInterface interface MyIntConsumer { void accept(int value); } // 使用时 IntStream.iterate(1, i -> i + 1).limit(12).forEach((MyIntConsumer) i -> s.submit(() -> waitTillFinished(cb)));
内容的提问来源于stack exchange,提问作者neela prasad
相关产品推荐
相关产品推荐

