当前位置: 首页 > 编程笔记 >

Java异常处理之try...catch...语句的使用进阶

隗翰海
2023-03-14
本文向大家介绍Java异常处理之try...catch...语句的使用进阶,包括了Java异常处理之try...catch...语句的使用进阶的使用技巧和注意事项,需要的朋友参考一下

try就像一个网,把try{}里面的代码所抛出的异常都网住,然后把异常交给catch{}里面的代码去处理。最后执行finally之中的代码。无论try中代码有没有异常,也无论catch是否将异常捕获到,finally中的代码都一定会被执行。
虽然 Java 执行时期系统所提供的预设处理器对除错很有用,你通常想要自己处理例外。这样做有两个优点:第一,它让你修正错误。第二,它可以避免程式自动终止。每当错误发生时,如果你的程式就停止而且列印出堆叠追踪,大多数的使用者都会感到很困惑。很幸运,你很容易就能避免这种情形。
要防备并且处理执行时期错误,只要将你要监视的程式码放在 try 区块里即可。在 try 区块之后紧接著在 catch 子句里指定你希望捕捉的例外型态
错误捕捉例子: 

try 
{ 
  code; //将自己的代码放在其中; 
} catch(e) //如果上面的代码有错误,这里就捕获 
{ 
  alert(e.number); //获得错误信息 
} 

 
例如:

import java.io.*;//调用io包
 public class SimpleCharInOut
 {
 public static void main(String args[])
  {
   char ch=' ';//定义个字符ch初始为‘ '
   System.out.println(" Enter a character please");//在屏幕上输出Enter a character please
   try {//你要监视的程式码放在 try 区块里即可。在 try 区块之后紧接著在 catch 子句里指定你希望捕捉的例外型态 
 
     ch=(char)System.in.read();//将从键盘输入的字符赋给ch
    }
   catch(IOException e) //如果上面的代码有错误,这里就捕获
    {  } ;//错误后不进行操作
 System.out.println("You're entered character:" + ch);// 在屏幕上输出You're entered character:
 //和ch的值
  }
 }

我们在写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又引入了一些有用的特性。在不需要考虑向后兼容的前提下, 适当并灵活运用一些语法特性,可以让我们的代码在一定程度上显得更清晰,更简洁。

 类似资料:
  • 本文向大家介绍C#异常处理中try和catch语句及finally语句的用法示例,包括了C#异常处理中try和catch语句及finally语句的用法示例的使用技巧和注意事项,需要的朋友参考一下 使用 try/catch 处理异常 try-catch 块的用途是捕捉和处理工作代码所生成的异常。 有些异常可以在 catch 块中处理,解决问题后不会再次引发异常;但更多情况下,您唯一能做的是确保引发适

  • 本文向大家介绍SQL Server 2005 中使用 Try Catch 处理异常,包括了SQL Server 2005 中使用 Try Catch 处理异常的使用技巧和注意事项,需要的朋友参考一下 TRY...CATCH是Sql Server 2005/2008令人印象深刻的新特性.提高了开发人员异常处理能力.没有理由不尝试一下Try.. Catch功能. * TRY 块 - 包含可能产生异常的

  • 在实际开发中,根据 try catch 语句的执行过程,try 语句块和 catch 语句块有可能不被完全执行,而有些处理代码则要求必须执行。例如,程序在 try 块里打开了一些物理资源(如数据库连接、网络连接和磁盘文件等),这些物理资源都必须显式回收。 Java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只回收堆内存中对象所占用的内存。 所以为了确保一定能回收 try 块中打开的物理资源,异

  • 我刚刚开始用java编写一个21点游戏。我试图让程序要求用户再次输入,如果他们输入的现金不是一个有效的整数。我看到许多带有catch的try语句示例,但没有一个是有效的。程序给出的错误InputMismatchException无法解析为类型。我遵循的一个线程就是这个,我有完全相同的代码,只是变量名不同。给你。Java输入不匹配异常 这是我的密码: 任何关于为什么我几乎精确的代码不起作用的帮助都将

  • 本文向大家介绍C++编程异常处理中try和throw以及catch语句的用法,包括了C++编程异常处理中try和throw以及catch语句的用法的使用技巧和注意事项,需要的朋友参考一下 若要在 C++ 中实现异常处理,你可以使用 try、throw 和 catch 表达式。 首先,使用 try 块将可能引发异常的一个或多个语句封闭起来。 throw 表达式发出信号,异常条件(通常是错误)已在 t

  • 问题内容: 在一个教程中,我发现 您的代码无法处理Unchecked Exception, 即我们不能使用块,示例是类似的异常,但是可以使用try / catch块处理这些异常。我认为我不清楚这个概念! 我也认为throw关键字只能与block.can一起使用吗? 问题答案: 已检查和未检查的异常之间的唯一区别是,必须使用捕获或在方法签名中声明 已 检查的异常,而对于未检查的异常,这是可选的。 您