一、try-catch语句
捕获异常是通过try-catch语句实现的,最基本try-catch语句语法如下:
try{ //可能会发生异常的语句 } catch(Throwable e){ //处理异常e }
1.try代码块
try代码块中应该包含执行过程中可能会发生异常的语句。一条语句是否有可能发生异常,这要 看语句中调用的方法。
如下:
public Date parse(String source) throws ParseException
方法后面的throws ParseException说明:当调用parse()方法时有可以能产生ParseException异常。
提示:静态方法、实例方法和构造方法都可以声明抛出异常,凡是抛出异常的方法都可以 通过try-catch进行捕获,当然运行时异常可以不捕获。一个方法声明抛出什么样的异常需要 查询API文档。
2.catch代码块
每个try代码块可以伴随一个或多个catch代码块,用于处理try代码块中所可能发生的多种异常。 catch(Throwable e)语句中的e是捕获异常对象,e必须是Throwable的子类,异常对象e的作用域在 该catch代码块中。
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //try-catch代码块 public class HelloWorld { public static void main(String[] args) { Date date = readDate(); System.out.println("日期="+date); } // 定义了一个静态方法来将字符串解析成日期 public static Date readDate(){ try { String str = "2020-2-9"; DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 从字符串中解析日期,解析方法可能有发生ParseException异常 Date date = dateFormat.parse(str); return date; } catch (ParseException e) { System.out.println("处理ParseException异常"); // e.printStackTrace()是打印异常堆栈跟踪信息 e.printStackTrace(); } return null; } }
运行结果:
日期=Sun Feb 09 00:00:00 CST 2020 Process finished with exit code 0
二、多catch代码块
如果try代码块中有很多语句会发生异常,而且发生的异常种类又很多。那么可以在try后面跟有多个catch代码块。多catch代码块语法如下:
try{ //可能会发生异常的语句 } catch(Throwable e){ //处理异常e } catch(Throwable e){ //处理异常e } catch(Throwable e){ //处理异常e }
注意:在多个catch代码情况下,当一个catch代码块捕获到一个异常时,其他的catch代码块就不再进行匹配。当捕获的多个异常类之间存在父子关系时,捕获异常顺序与catch代码块的顺序有关。一般 先捕获子类,后捕获父类,否则子类捕获不到。
代码如下:
import java.io.*; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //多catch代码块 public class HelloWorld1 { public static void main(String[] args) { Date date = readDate(); System.out.println("日期="+date); } public static Date readDate(){ FileInputStream readfile = null; InputStreamReader ir = null; BufferedReader in = null; try { // 调用FileInputStream()构造方法可能会发生FileNotFoundException异常 readfile = new FileInputStream("readme.txt"); ir = new InputStreamReader(readfile); in = new BufferedReader(ir); // 读取文件中的一行数据, 调用BufferedReader输入流的readLine()方法可能会发生IOException异常 String str = in.readLine(); if (str == null){ return null; } // 调用SimpleDateFormat()方法可能会发生ParseException异常 DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); java.util.Date date = df.parse(str); return date; // 应该先捕获FileNotFoundException异常后捕获IOException(先捕获子类异常) } catch (FileNotFoundException e) { System.out.println("处理FileNotFoundException"); e.printStackTrace(); } catch (IOException e) { System.out.println("处理IOException"); e.printStackTrace(); } catch (ParseException e) { System.out.println("处理ParseException"); e.printStackTrace(); } return null; } }
运行结果:
处理FileNotFoundException 日期=null java.io.FileNotFoundException: readme.txt (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at 异常处理类.捕获异常.HelloWorld1.readDate(HelloWorld1.java:29) at 异常处理类.捕获异常.HelloWorld1.main(HelloWorld1.java:19)
如果将FileNotFoundException和IOException捕获顺序调换,代码如下:
try{ //可能会发生异常的语句 } catch (IOException e) { // IOException异常处理 } catch (FileNotFoundException e) { // FileNotFoundException异常处理 }
那么第二个catch代码块永远不会进入,FileNotFoundException异常处理永远不会执行。 由于上述代码ParseException异常与IOException和FileNotFoundException异常没有父子关系,捕获ParseException异常位置可以随意放置。
三、try-catch语句嵌套
代码如下:
import java.io.*; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //try-catch语句嵌套 public class HelloWorld2 { public static void main(String[] args) { Date date = redaDate(); System.out.println("日期="+date); } public static Date redaDate(){ FileInputStream readfile = null; InputStreamReader ir = null; BufferedReader in = null; try { // 调用FileInputStream()构造方法可能会发生FileNotFoundException异常,如果外层出现异常先捕获外层异常 readfile = new FileInputStream("readme.txt"); ir = new InputStreamReader(readfile); in = new BufferedReader(ir); try { // 读取文件中的一行数据, 调用BufferedReader输入流的readLine()方法可能会发生IOException异常 String str = in.readLine(); if(str == null){ return null; } // 调用SimpleDateFormat()方法可能会发生ParseException异常 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = dateFormat.parse(str); return date; } catch (ParseException e) { System.out.println("处理ParseException"); e.printStackTrace(); } catch (IOException e) { System.out.println("处理IOException"); e.printStackTrace(); } } catch (FileNotFoundException e) { System.out.println("处理FileNotFoundException"); e.printStackTrace(); } return null; } }
总结:程序执行时外层捕获到异常,其他的catch代码块就不再进行匹配。若外层没有捕获到异常则捕获内层异常,程序执行时内层如果会发生异常,首先由内层catch进行捕获,如果捕获不到,则由外层catch捕获。
四、多重捕获
1.为什么使用多重捕获
多catch代码块客观上提高了程序的健壮性,但是程序代码量大大增加。如果有些异常虽然种类不同,但捕获之后的处理是相同的,看如下代码。
try{ //可能会发生异常的语句 } catch (FileNotFoundException e) { //调用方法methodA处理 } catch (IOException e) { //调用方法methodA处理 } catch (ParseException e) { //调用方法methodA处理 }
2.如何使用多重捕获
Java 7推出了多重捕获(multi-catch)技术,可以帮助解决此类问题,上述代码修改如下:
try{ //可能会发生异常的语句 } catch (IOException | ParseException e) { //调用方法methodA处理 }
在catch中多重捕获异常用“|”运算符连接起来。
注意 :什么不写成FileNotFoundException | IOException | ParseException 呢?这是因 为由于FileNotFoundException属于IOException异常,IOException异常可以捕获它的所有子类异常了。