Java SE 7 Exception的使用
在Java SE 7 中,作为Project Coin项目中众多有用的细小语言变化之一的加强型异常处理,现在来学习如何利用它。
简介:
在这边文章中,我们所涉及的一些变化是作为Java平台标准版7(Java SE 7)所发布,在JSR334(Java Specification Request)有详细的说明。现在我们重点讨论异常处理,特别是:multi-catch,rethrow,以及try-with-resources.
Multi-Catch Exceptions
多异常捕获已经加入到Java SE 7,他帮助我们更简便的进行异常处理,现在就把你的异常处理代码从Java SE7之前的版本迁移到Java SE7来阅读。
例1:
public class ExampleExceptionHandling
{
public static void main( String[] args )
{
try {
URL url = new URL("http://www.yoursimpledate.server/");
BufferedReader reader = new
BufferedReader(newInputStreamReader(url.openStream()));
String line = reader.readLine();
SimpleDateFormat format = new SimpleDateFormat("MM/DD/YY");
Date date = format.parse(line);
}
catch(ParseException exception) {
// handle passing in the wrong type of URL.
}
catch(IOException exception) {
// handle I/O problems.
}
catch(ParseException exception) {
// handle date parse problems.
}
}
}
在过去,如果你想要相同的逻辑代码在上面的三个异常代码块的时候,你不得不在PaseException和IOException中拷贝粘贴代码,一个缺乏经验或者懒惰的程序员可能认为像下面这样也是OK的。
例2:
public class ExampleExceptionHandlingLazy
{
public static void main( String[] args )
{
try {
URL url = new URL("http://www.yoursimpledate.server/");
BufferedReader reader = new
BufferedReader(new InputStreamReader(url.openStream()));
String line = reader.readLine();
SimpleDateFormat format = new SimpleDateFormat("MM/DD/YY");
Date date = format.parse(line);
}
catch(Exception exception) {
// I am an inexperienced or lazy programmer here.
}
}
}
在例2代码示例中最大的毛病就是会产生不可预料的副作用,任何代码在try代码块可能产生异常,所有异常将全部由catch子句所处理。如果一个异常既不是ParseException也不是IOException(例如:SecurityException),此异常仍然会被捕获,但是上游用户去不知道真正发生了什么?这种吞并式的异常将很难调试。
为了方便程序员,JavaSE7现在引入了多异常捕获,这样程序员就可以合并多个catch字句为一个单独的代码块,而不需要去使用危险的吞并似的一个异常捕获所有,或者拷贝整个代码块。
例3:
public class ExampleExceptionHandlingNew
{
public static void main( String[] args )
{
try {
URL url = new URL("http://www.yoursimpledate.server/");
BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream()));
String line = reader.readLine();
SimpleDateFormat format = new SimpleDateFormat("MM/DD/YY");
Date date = format.parse(line);
}
catch(ParseException | IOException exception) {
// handle our problems here.
}
}
}
示例3就展示了怎么合理的合并两个catch块语句,注意catch子句的语法(ParseException|IOException),catch子句可以捕获ParseException和IOException。所以如果想多个不同的异常共用相同的异常处理代码,那么就可以使用这种管道语法(ExceptionType…|ExceptionType variable)。
Rethrowing Exceptions
当你在处理异常的时候,有时候想把一个处理完后的异常往外抛的时候,没有经验的程序员可能认为用下面这种方式操作是合理的
例4:
public class ExampleExceptionRethrowInvalid
{
public static void demoRethrow()throws IOException {
try {
// forcing an IOException here as an example,
// normally some code could trigger this.
throw new IOException(“Error”);
}
catch(Exception exception) {
/*
* Do some handling and then rethrow.
*/
throw exception;
}
}
public static void main( String[] args )
{
try {
demoRethrow();
}
catch(IOException exception) {
System.err.println(exception.getMessage());
}
}
}
很遗憾的是编译器没发完成编译工作,下面这段代码展示了如何去处理完异常后再往外抛。
例5:
public class ExampleExceptionRethrowOld
{
public static demoRethrow() {
try {
throw new IOException("Error");
}
catch(IOException exception) {
/*
* Do some handling and then rethrow.
*/
throw new RuntimeException(exception);
}
}
public static void main( String[] args )
{
try {
demoRethrow();
}
catch(RuntimeException exception) {
System.err.println(exception.getCause().getMessage());
}
}
}
上面这个例子的毛病就在于不能抛出原生的异常,他用另外一个异常包裹了,这就意味着代码的下游需要注意他是被包装了的。所以为了捕获到这个确切的原生异常,在Java SE7中做出变化是必须的,如下代码:
例6:
public class ExampleExceptionRethrowSE7
{
public static demoRethrow() throws IOException {
try {
throw new IOException("Error");
}
catch(Exception exception) {
/*
* Do some handling and then rethrow.
*/
throw exception;
}
}
public static void main( String[] args )
{
try {
demoRethrow();
}
catch(IOException exception) {
System.err.println(exception.getMessage());
}
}
}
上面的示例在JavaSE7中能正确的编译(译者注)
Try-with-Resources
你可能注意到了在第一个例子中有这样一个问题(这就是为什么当你不知道示例代码做了些什么的时候,你永远也不要在生产环境中使用)。这个问题就是没有对资源的清空。例7是一个修改的版本,描述了怎样在JavaSE7之前的版本中校正这个问题。
例7:
public class ExampleTryResources
{
public static void main(String[] args)
{
BufferedReader reader = null;
try {
URL url = new URL("http://www.yoursimpledate.server/");
reader = new BufferedReader(new
InputStreamReader(url.openStream()));
String line = reader.readLine();
SimpleDateFormat format = new SimpleDateFormat("MM/DD/YY");
Date date = format.parse(line);
}
catch (MalformedURLException exception) {
// handle passing in the wrong type of URL.
} catch (IOException exception) {
// handle I/O problems.
} catch (ParseException exception) {
// handle date parse problems.
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
我们注意到代码中添加了一个final代码块,如果BufferedReader被赋值了,它将被关闭,而且变量reader也已经移到了try代码块的外面了。当一个I/O异常发生的时候关闭字符流就要多些很多的代码。
在JavaSE7中,可以更简洁更清爽,如例8所示,这种新的语法允许你把资源作为try代码块的一部分,这意味着可以提前定义好资源然后执行完try代码块的时候虚拟机将自动关闭资源。
例8:
public static void main(String[] args)
{
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
new URL("http://www.yoursimpledate.server/").openStream())))
{
String line = reader.readLine();
SimpleDateFormat format = new SimpleDateFormat("MM/DD/YY");
Date date = format.parse(line);
} catch (ParseException | IOException exception) {
// handle I/O problems.
}
}
在例8中实际发生变化的是在try(….)语句,需要注意的是这个特性只有在资源实例实现了AutoCloseable接口的实例才能生效
总结:
异常处理在javaSE7中,你不仅可以写出更简洁的程序,正如multi-catch示例所演示的一样,而且在可以处理完部分异常后再往外抛出去。如re_throw 例子所示,JavaSE7同样有助于减少易于出错的异常清理。正如我们在try-with resource例子中看到的一样。这些特征和其他Project Coin项目中提供的一样,能使Java程序员写代码更有效率以及写出更高效的代码。
附上自己的一点感受:第一次这样认真的去翻译一遍文章,以往看完一遍文章可以不到二十分钟,但是翻译工作花了我两个小时,非常认真的在做,发现翻译不仅可以学外语,还可以学语文。对自己的语言组织也有提高,终于体会到翻译书籍的人特别不容易。2012/3/1 1:20
原文连接http://www.oracle.com/technetwork/articles/java/java7exceptions-486908.html