总览
Java 8添加了诸如lambda和类型推断之类的功能。 这使语言不那么冗长和简洁,但是它带来了更多的副作用,因为您不必对所做的事情那么明确。
Lambda的返回类型很重要
Java 8推断闭包的类型。 一种方法是查看返回类型(或是否返回任何内容)。 这可能会产生令人惊讶的副作用。 考虑下面的代码。
es.submit(() -> {try(Scanner scanner = new Scanner(new FileReader("file.txt"))) {String line = scanner.nextLine();process(line);}return null;
});
此代码可以正常编译。 但是,该行返回null; 似乎是多余的,您可能很想删除它。 但是,如果删除该行,则会出现错误。
Error:(12, 39) java: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown
这是在抱怨FileReader的使用。 返回null与捕获未捕获的异常有什么关系!
类型推断
ExecutorService.submit()是一个重载方法。 它有两种采用一个参数的方法。
- ExecutorService.submit(Runnable runnable);
- ExecutorService.submit(Callable callable);
这两种方法都没有参数,那么javac编译器如何推断lambda的类型? 它查看返回类型。 如果返回null; 它是Callable <Void>,但是如果不返回任何内容(甚至不返回null),则它是aRunnable。
Callable和Runnable具有另一个重要区别。 Callable引发检查异常,但是Runnable不允许引发检查异常。
返回null的副作用是您不必处理已检查的异常,这些异常将存储在Future <Void> Submit()返回中。 如果不返回任何内容,则必须处理已检查的异常。
结论
尽管lambda和类型推断会删除大量的样板代码,但您会发现更多的边缘情况,在这种情况下,编译器推断的隐藏细节可能会有些混乱。
脚注
您可以使用类型转换明确说明类型推断。 考虑一下:
Callable<Integer> calls = (Callable<Integer> & Serializable) () -> { return null; }
if (calls instanceof Serializable) // is true
这种石膏有许多副作用。 不仅call()方法返回一个Integer并且添加了标记接口,为lambda生成的代码也发生了变化,即,它添加了writeObject()和readObject()方法来支持lambda的序列化。
注意:每个调用站点都会创建一个新类,这意味着此转换的详细信息在运行时通过反射可见。
翻译自: https://www.javacodegeeks.com/2014/09/lambdas-and-side-effects.html