考虑下面写文件的函数:
这个方法背后的想法是允许用户传入InputStream的不同实现方法。所以writeToFile能被
GZIPOuputStream, SnappyOuputStream(快速压缩)或者只是一个普通的FileInputStream调用。
private static void writeToFile(File file, String value,
Function<OutputStream, OutputStream> writing) throws IOException{
try (PrintWriter pw = new PrintWriter(new BufferedOutputStream
(writing.apply(new FileOutputStream(file))))) {
pw.write(value);
}
这个整洁的方法能被这样调用
public static void main(String[] args) {
try {
//Write with compression
//DOES NOT COMPILE!!
writeToFile(new File("test"), "Hello World", GZIPOutputStream::new);
//Just use the FileOutputStream
writeToFile(new File("test"), "Hello World", i->i);
}catch(IOException e){
//deal with exception as you choose
}
}
不幸的是正如注释中所指出的这段代码编译不通过。不编译的原因是因为GZIPOutputStream在它的构造器里抛出了一个IOException。如果IOException在lambda之外被抛出,就可以用一个try catch块来处理。但是lambdas不是这样工作的。
事实上你这样处理异常可以让它正常编译:
public static void main(String[] args) {
try {
//Write with compression
//COMPILES BUT SO UGLY
writeToFile(new File("test"), "Hello World", i -> {
try {
return new GZIPOutputStream(i);
} catch (IOException e) {
//HOW ARE WE SUPPOSED TO DEAL WITH THIS EXCEPTION??
throw new AssertionError(e);
}
});
//Just use the FileOutputStream
writeToFile(new File("test"), "Hello World", i->i);
}catch(IOException e){
//deal with exception as you choose
}
}
这样做不仅代码丑陋,你还留下了一个棘手的问题,就是IOExceptin怎么处理。在这种情况下我们只要在一个AssertionError内部重新打包。看我上一编文章“欺骗异常”中用正确的方式来处理这种情况。
但是这个问题有一个解决方案。不是用java.util.function.Function 传一个值和返回一个值,我们能创建一个传一个值、返回一个值和抛出一个异常的自定义函数。用这种方式的话,
writeToFile的客户端代码就非常简洁干净,还能用自然的方式来处理这个异常。此外,lambdas
现在这种使用方式是为了让我们的代码变得更漂亮易懂。
完整代码清单
package util;
import java.io.*;
import java.util.zip.GZIPOutputStream;
public class LambdaExceptions {
public static void main(String[] args) {
try {
//Write with compression
writeToFile(new File("test"), "Hello World", GZIPOutputStream::new);
//Just use the FileOutputStream
writeToFile(new File("test"), "Hello World", i->i);
}catch(IOException e){
//deal with exception as you choose
}
}
private static void writeToFile(File file, String value,
ThrowingFunction<OutputStream, OutputStream, IOException> writing) throws IOException{
try (PrintWriter pw = new PrintWriter(new BufferedOutputStream
(writing.apply(new FileOutputStream(file))))) {
pw.write(value);
}
}
@FunctionalInterface
public interface ThrowingFunction<I, O, T extends Throwable> {
O apply(I i) throws T;
}
}