码迷,mamicode.com
首页 > 编程语言 > 详细

欺骗异常 – Java 8 Lambdas

时间:2015-05-21 15:37:03      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:java8   lambda   j2se   

抛开检查异常和运行时异常的宗教争论,有很多次那些处理检查异常的例子的可怜构造类库就能让你发疯。

考虑下面你可能想要写的一小段代码:

public void createTempFileForKey(String key) {
  Map<String, File> tempFiles = new ConcurrentHashMap<>();
  //不编译,因为抛出了IOException
  tempFiles.computeIfAbsent(key, k -> File.createTempFile(key, ".tmp"));
}

为了正常编译你需要捕获这个异常。代码如下:

public void createTempFileForKey(String key) {
    Map<String, File> tempFiles = new ConcurrentHashMap<>();
    tempFiles.computeIfAbsent(key, k -> {
        try {
            return File.createTempFile(key, ".tmp");
        }catch(IOException e) {
            e.printStackTrace();
            return null;
        }
    });
}

尽管这段代码能正常编译,实际上IOException已经被吞掉了。这个方法的用户应该被通知已经抛出了一个异常。

为了解决这个你可以把IOException包装成一个范型的RuntimeException,如下:

public void createTempFileForKey(String key) throws RuntimeException {
    Map<String, File> tempFiles = new ConcurrentHashMap<>();
    tempFiles.computeIfAbsent(key, k -> {
        try {
            return File.createTempFile(key, ".tmp");
        }catch(IOException e) {
            throw new RuntimeException(e);
        }
    });
}

这段代码抛出了一个异常,但不是这段代码应该自然抛出的那个IOException。对那些支持RuntimeExceptions的人来说, 这段代码可能会让他们高兴。尤其解决方案是重新定义了一个自定义的IORuntimeException.不过大多数人编码的方式是,他们期望他们的方法能从File.createTempFile方法抛出检查时IOException.

这样做的自然方式有一点复杂,像这样:

public void createTempFileForKey(String key) throws IOException{
        Map<String, File> tempFiles = new ConcurrentHashMap<>();
        try {
            tempFiles.computeIfAbsent(key, k -> {
                try {
                    return File.createTempFile(key, ".tmp");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }catch(RuntimeException e){
            if(e.getCause() instanceof IOException){
                throw (IOException)e.getCause();
            }
        }
}

从lamabda内部,你必须捕获异常,把它包装成一个RuntimeException并抛出这个RuntimeException.lambda必须捕获这个RuntimeException解包并重新抛出这个IOException.所有这些的确非常丑陋。

理想的做法是在lamabda内部抛出一个检查异常,不用改变computeIfAbsent的声明。换句话说,如果是一个运行时异常就抛出一个检查异常。但不幸的是Java不会让我们这样做。

除非我们作弊。下面的两个方法精确的做到了我们想要的,假如是一个运行时异常就抛出一个检查异常。

方法1—-用范型

public static void main(String[] args){
        doThrow(new IOException());
    }

    static void doThrow(Exception e) {
        CheckedException.<RuntimeException> doThrow0(e);
    }

    static <E extends Exception>
      void doThrow0(Exception e) throws E {
          throw (E) e;
    }

注意我们创建并抛出了一个没有在main方法里声明的IOException。

方法2—用Unsafe类:

public static void main(String[] args){
        getUnsafe().throwException(new IOException());
    }

    private static Unsafe getUnsafe(){
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            return (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

我们又一次设法抛出了一个没有在其方法里声明的IOException。不管你更喜欢哪个方法,我们现在可以用这种方式自由地写原始代码。

public void createTempFileForKey(String key) throws IOException{
        Map<String, File> tempFiles = new ConcurrentHashMap<>();

        tempFiles.computeIfAbsent(key, k -> {
            try {
                return File.createTempFile(key, ".tmp");
            } catch (IOException e) {
                throw doThrow(e);
            }
        });
    }

    private RuntimeException doThrow(Exception e){
        getUnsafe().throwException(e);
        return new RuntimeException();
    }

    private static Unsafe getUnsafe(){
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            return (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

doThrow()方法明显的包装在了一些工具类里,这样可以使你在createTempFileForKey()方法中的代码更加简洁。

欺骗异常 – Java 8 Lambdas

标签:java8   lambda   j2se   

原文地址:http://blog.csdn.net/supercrsky/article/details/45891741

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!