lambda表达式的副作用

[b]概述[/b]

Java 8添加了lambda表达式及类型推导的特性。这使得语言更加简练和整洁,然而正因这样,你没有明确说明自己究竟要做什么,这也带来了一些副作用。

[b]lambda表达式的返回值很重要[/b]

Java 8会去推导闭包的类型。推导的一个方式就是去查看它的返回值(或者是否有返回值)。而这带来的副作用令人咋舌。看下这段代码。




ExecutorService es = Executors.newSingleThreadExecutor();

es.submit(() -> {
try(Scanner scanner = new Scanner(new FileReader("file.txt"))) {
String line = scanner.nextLine();
process(line);
}
return null;
});



这段代码能够通过编译。然而,return null的这行,显得有些多余,你可能会想把它删掉。然而一旦你删掉了这行,它就会报错了。




Error:(12, 39) java: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown




这是使用FileReader的时候在报错。return null和捕获这个异常到底有什么关系?

[b]类型推导[/b]

ExecutorService.submit()是一个重载的方法。它有两个带单个参数的方法。

ExecutorService.submit(Runnable runnable);

ExecutorService.submit(Callable callable);

这些方法都不带参数,那么javac编译器如何能推导出lambda表达式的类型?它看的是返回值。如果你返回null,那就是Callable<Void>,然而如果不返回值,连null都没有了,那就是Runnble。

Callable和Runnable有一个重要的区别。Callable会抛出受检查异常,而Runnable则没有。

返回null的一个副作用就是你无需处理受检查异常,它们会在Future<Void> submit()中一起返回。如果你不返回任何东西的话,你就得自己去处理异常。

[b]结论[/b]

尽管lambda表达式和类型推导减少了许多模板代码,然而你会发现大量的边缘用例,那里编译器推导背后的隐藏细节会让人摸不着头脑。

[b]补充[/b]

你可以使用显式转换来进行类型推导。像这样




Callable<Integer> calls = (Callable<Integer> & Serializable) () -> { return null; }
if (calls instanceof Serializable) // is true



这个类型转换有一个副作用。call()方法不仅要返回一个Integer,它还添加了一个标记接口,lambda表达式生成的代码会因此改变,也就是说,它会增加一个writeObject()方法以及readObject()方法以支持lambda表达式的序列化。

注意:每个调用点都会生成一个新类,也就是说通过反射这个转换的细节是运行时可见的。


原创文章转载请注明出处:[url=http://it.deepinmind.com/java/2014/09/25/lambdas-and-side-effects.html]http://it.deepinmind.com[/url]


[url=http://vanillajava.blogspot.sg/2014/09/lambdas-and-side-effects.html]英文原文链接[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值