0、Java的异常体系
1、异常概述
异常机制已经成为判断一门编程语言是否成熟的标准,目前主流的编程语言都提供了成熟的异常机制,增加了异常处理机制后的程序有更好的容错性,更加健壮 Java的异常机制主要依赖于:try、catch、finally、throws和throw Java7进一步增强了异常处理机制的功能,包括带资源的try语句、捕获更多异常的catch Java将异常分为两种,Checked异常和Runtime异常,Checked异常都是可以在编译阶段被处理的异常,程序强制要求处理;而Runtime异常是运行时产生的异常2、异常处理机制
使用try…catch捕获异常 try{…}catch(Exception e){…} 如果执行try块里的业务逻辑代码时出现异常,系统自动生成一个异常对象,该异常对象被提交给Java运行时环境,这个过程被称为抛出(throw)异常 当Java运行时环境收到异常对象时,会寻找能处理该异常对象的catch块,如果找到合适的则把该异常对象交给该catch块处理,这个过程被称为捕获异常,否则运行时环境终止,Java程序也将退出3、异常的继承关系
Java把所有非正常情况分成两种:异常(Exception)和错误(Error),它们都是继承Throwable父类 Error错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断;通常应用程序无法处理这些错误,因此也无法捕获 开发中常遇到的内存溢出是属于错误(Error) 第一种:OutOfMemoryError: PermGen space内存空间不足,如一次性加载太多信息,或加载项目太多 第二种:OutOfMemoryError: Java heap spacejava虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了 第三种:OutOfMemoryError:unable to create new native thread一般很少出现,可能由于分配给JVM内存与系统本身比例问题引起 Java7可以提供更多异常捕获 try{…}catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException ie){…} 访问异常信息 getMessage():返回该异常的详细描述字符串 printStackTrace():将该异常的跟踪栈信息输出到标准错误输出 printStackTrace(PrintStream s):将该异常的跟踪信息输出到指定输出流 getStackTrace():返回该异常的跟踪栈信息4、finally块
try{ ...}catch(Exception e){ ...}finally{ ...}不管try块中的代码是否出现异常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return、throw语句,finally块总是被执行 异常处理语法结构中只有try块是必须的,catch块和finally块都是可选的,但两者至少出现其中之一;可以有多个catch块,catch块必须位于try之后,finally必须位于所有catch块之后; 如果在异常处理代码中使用System.exit(1)语句来退出虚拟机,则finally块将失去执行的机会 在通常情况下,不要在finally块中使用如return或throw等导致方法终止的语句,否则会导致try块、catch块中的return、throw语句失效
5、Java7自动关闭资源的try语句
try(BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));){ System.out.println(br);} catch (Exception e) { e.printStackTrace();}Java7增强了try语句的功能,允许在try关键字后紧跟一对圆括号声明、初始化一个或多个资源,try语句在该语句结束时自动关闭这些资源;而且这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口就必须实现close()方法 以上的BufferedReader都是实现了Closeable接口的,即使没有finally块也会自动关闭资源
6、Checked异常和Runtime异常体系
所有的RuntimeException类及其子类的实例被称为Runtime异常;非RuntimeException类及其子类的异常实例则被称为Checked异常 Checked异常处理方式: 当前方法明确知道如何处理该异常,程序应该使用try…catch块来捕获该异常,然后再对应的catch块中修复该异常 当方法不知道如何处理这种异常,应该在定义该方法时抛出该异常 Runtime异常则无须显示声明抛出,程序也可以通过try…catch块来捕获7、使用throws声明抛出异常
public class ThrowsTest{ public static main(String[] args)throws IOException{ FileInputStream fis = new FileInputStream("a.txt"); }}
- 当前方法不知道如何处理这种类型异常时可以使用throws声明抛出异常
- 使用throws声明抛出异常时有一个限制:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,子类方法声明抛出异常不允许比父类方法声明抛出的异常多
8、使用throw抛出异常
当程序出现错误时,系统会自动抛出异常,除此之外,Java也允许程序自行抛出异常,使用throw语句来完成9、自定义异常类
用户自定义异常都应该继承Exception基类,如果系统自定义Runtime异常,则应该继承RuntimeException基类public class MyException extends Exception{ public MyException(){} public MyException(String msg){ super(msg); } publc MyException(Throwable t){ super(t); }}
10、catch和throw同时使用
为了实现通过多方协作处理同一个异常的情形,可以在catch块中结合throw语句来完成,将异常传递给下一个程序 Java7可以直接将捕获的异常直接传递:try{ new FileOutputStream("a.txt");}catch(Exception ex){ ex.printStackTrack(); throw ex;}
11、异常链
public calSal() throws MyException{ try{ ... }catch(Exception e){ throw new MyException(e); }}
12、异常处理规则
- 成功的异常处理应该实现4个目标:
使程序代码混乱最小化
捕获并保留诊断信息 通知合适的人员 采用合适的方式结束异常活动- 避免过度依赖异常:
把异常和普通错误混淆在一起,不再编写任何错误处理代码
使用异常处理来替代流程控制- 不要使用过于庞大的try块
应该把大块的try块分割成多个可能出现异常的程序段落,并把它们放在单独的try块中