文档章节

谈谈Java的try..catch...

mj4738
 mj4738
发布于 2014/06/07 11:00
字数 1221
阅读 3591
收藏 12

我们在写Java的try..catch的时候,往往需要在最后加上finally子句关闭一些IO资源,比如

InputStream is;
try{
    is=openInputStream();
    // do something
}catch(IOException e){
    e.printStaceTrace(e);
}finally{
    try{
        is.close();
    }catch(IOException e ){
    }
}

但是在使用这种模式时,即使是Java老手,偶尔也会犯一些错误。比如上面这段代码,当openInputStream()函数在执行过程中抛出异常,那么变量is的值仍为null,此时执行is.close()会抛出NullPointerException. 由于NullPoiterException不是IOException的子类,因此它不能被catch块捕获,而是直接往调用层抛出去. 一种改进的写法就是在关闭流的时候先进行非空判断,但这样代码会显得很啰嗦。个人认为比较优雅的写法是直接调用commons-io包提供的IOUtils.closeQuitely()方法关闭流(或者自己封装一个closeQuitely()方法)。

使用这种写法还有一种好处,就是当遇到关闭多个IO资源时不容易出错,比如下面这段代码: 

InputStream is;
OutputStream os ;
try{
    is=openInputStream();
    // do something
}catch(IOException e){
    e.printStaceTrace(e);
}finally{
    try{
        if (is != null )  is.close();
        if (os != null )  os.close();
    }catch(IOException e ){
    }
}

当is.close()发生错误的时候,os.close()就无法被执行,从而导致os所引用的资源没有被释放。 

也许Oracle也觉得这种try .. catch ... finally的样板代码太没必要,因此在JDK 7中对try 子句进行了一些改造,免去编写一些手动关闭资源的代码,让代码看起来更紧凑更简洁。比如上面的代码在JDK 7下可以改成:

try(
 InputStream is = openInputStream();
 OutputStream os = openOutStream();
){
  // do something 
}catch(IOException e){
    e.printStaceTrace(e);
}

Oracle把这里的try(..)语句叫做try-with-resource语句。需要注意的是,try(.. )中变量所引用的对象都必须是实现了java.io.AutoClosable接口的实例,当退出try ..catch块时,JDK会自动调用close()方法。 也就是说,try-with-resource语句中的resource(资源)不仅限于IO资源。 

 

这里有必要对try-with-resource语句的一些细节进行补充说明: 

  • JDK会确保所有资源的close()方法被调用,不管close()方法是否抛出异常, 而调用的顺序和资源声明的顺序相反

  • try-with-resource语句中所有抛出的异常都会被捕获。如果多个异常被抛出,后面所抛出的异常会被suppress(抑制)在前一个异常中,catch块最终只拿到最先抛出的那个异常。可以依次通过调用Throwable类定义的getSuppressed()获得被suppressed(抑制)的异常

还是上面那个例子,

  • 当退出try .. catch.块的时候,JDK会先调用os.close(),然后是is.close(), 如果两次close()都抛出IOException, 那么is.close()所抛出的异常会被suppress(抑制)在os.close()所抛出的异常中,最终catch块只捕获到os.close()所抛出的异常。可以通过getSuppressed()方法拿到is.close()所抛出的异常。

  • 如果调用openInputStream()的时候就发生IOException,那么openOutputStream()就不会被调用,os.close()和is.close()也不会被调用, catch块捕捉到 调用openInputStream()时所抛出的异常。 

  • 如果调用openOutputStream()发生IOException(用记号 e1表示), 那么is.close()还是会被调用,  如果此时is.close()又抛出IOException(用记号 e2表示),那么e2会被suppress到e1中,而catch块捕捉到的异常是 e1. 

 

除了对try块做了改造,JDK 7还对catch部分进行了简化,允许把多个catch子句合并。 比如: 

try(
 InputStream is = openInputStream();
 OutputStream os = openOutStream();
){
  // do something   
}catch(IOException  | XMLParseException | XPathException e){
    e.printStaceTrace(e);
}

 

此外,当你重新抛出多个异常时,不再需要详细定义异常类型了,编译器已经知道你具体抛出的是哪个异常了你只需在方法定义的时候声明需要抛出的异常即可。比如

// 虽然这里用Exception匹配抛出的IOException,到编译器知道实际上抛给上层的异常是IOException
        public void doIO() throws IOException {
            try{
                throw new IOException();
            }catch(Exception e){
                throw e;
            }
        }

PS : 这个特性我想不到会带来什么好处

 

JDK 7还有其他有趣的语法新特性,比如二进制字面量,用下划线分割长数字,泛型参数的类型推断,switch支持字符串匹配等等。 现在JDK 8又引入了一些有用的特性。在不需要考虑向后兼容的前提下, 适当并灵活运用一些语法特性,可以让我们的代码在一定程度上显得更清晰,更简洁。


© 著作权归作者所有

mj4738

mj4738

粉丝 294
博文 489
码字总数 119327
作品 0
崇明
高级程序员
Java学习系列文章:说说Java中的异常

在正常的程序设计中,程序异常处理是非常关键和重要的一部分。试想一个项目中没有一个好的异常处理,这个项目会怎么样? 什么是异常 异常其实是程序上的错误,包括程序逻辑错误和系统错误。比...

java高级架构牛人
06/29
0
0
通俗理解运行时异常和非运行时异常(一般异常) 

通俗理解运行时异常和非运行时异常(一般异常) 一,异常的概念 Java异常类层次结构图: Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子...

DemonsI
09/13
0
0
Java学习---Java简单认识

前言 小编在学习Java方面的基础知识,发现里面有很多是结合之前的语言的特点发展过来的,不同的地方是,Java有它自己的发展和特点。下面小编先简单地做一下总结,结合看过的1-2章的J2SE视频,...

m18633778874
04/01
0
0
百词斩Java程序员面试11个问题,你会几个?2018-04-10

近日,我们在w3cschool app开发者头条上,可以看到百词斩Java程序员面经。 在分享百词斩Java面经前,w3cschool特别给程序员小伙伴们带来一些Java学习干货: 0、学习Java必备的3大神器 如果你...

W3Cschool
04/10
0
0
Java面试中,遇到这类面试题最吃亏!

从你接触 Java开发到现在,你对 Java最直观的印象是什么呢?是它宣传的 “Compile once, run anywhere”,还是目前看已经有些过于形式主义的语法呢?你对于 Java平台到底了解到什么程度?请你...

Java大蜗牛
07/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

docker update:更新一个或多个容器的配置

更新容器的配置 docker update:更新一个或多个容器的配置。 具体内容请访问:https://docs.docker.com/engine/reference/commandline/update/#options 语法:docker update [OPTIONS] CONTA...

lwenhao
32分钟前
1
0
unload事件

unload事件不触发的原因分析 1.代码位置不对,应该优先加载,不能放到回调函数中 2.浏览器不支持 3.最可能的原因,unload事件中触发的函数是一个异步执行的函数,浏览器是不允许在窗口关闭之后在...

狮子狗
45分钟前
1
0
DbForge Schema Compare for MySQL入门教程:如何连接到数据库

【dbForge Schema Compare for MySQL下载】 要创建连接: 1. 在“Connection” 工具栏上单击“New Connection”按钮 。 2. 在“Host” 框中输入主机名。 3. 在“Port” 框中输入端口信息。默...

Miss_Hello_World
47分钟前
1
0
公众号关联微信小程序

公众号关联小程序发送关联通知,对于推广小程序有着很大的帮助。所以问题来了,怎么做到在公众号关联小程序发送关联通知呢? 一:开发中遇到的问题 之前在开发过程中发现,公众号已经关联小程...

Code辉
今天
1
0
并发编程基础之JMM学习摘要

一、JMM定义 Java内存模型即Java Memory Model(JMM),JMM决定一个线程对共享变量的写入何时对另一个线程可见(内存可见性),从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程...

狠一点
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部