1.异常处理机制
Java提供了丰富的异常类,把所有的非正常情况分为两种:异常(Exception)和错误(Error),它们都继承Throwable父类。
Error错误,一般是指与虚拟机有关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。
进行异常捕获时不仅因该把Exception类对应的catch块放在最后,而且所有父类异常的catch块都应该排在子类异常catch块的后面,即,先处理小异常,再处理大异常。
多异常捕获
- 捕获多种类型的异常时,多种异常类型之间用竖线(|)隔开
- 捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不能对异常变量重新赋值
访问异常信息
异常对象包含的常用方法:
- getMessage():返回该异常的详细描述字符串
- printStackTrace():将该异常的跟踪栈信息输出到指定输出流
- printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流
- getStackTrace():返回该异常的跟踪栈信息
使用finally回收资源
有时候程序在try块里打开了一些物理资源,例如数据库连接、网络连接和磁盘文件等,这些物理资源都必须显式回收。
注:Java的垃圾回收机制不会回收任何物理资源,只能回收堆内存中对象所占用的内存
如果catch块里包含return强制返回语句,也一定会先执行finally块里的代码。但如果在异常处理代码中使用System.exit(1)语句来推出虚拟机,则finally块将失去执行的机会。
通常情况下,不要在finally块中使用如return或throw等导致方法终止的语句。一旦在finally块中使用了return或throw语句,将会导致try块、catch块中的return、throw语句失效。因为程序执行try、catch块遇到return、throw语句之后会去寻找该异常处理流程中是否包含finally块,如果有finally块则程序执行完finally块之后系统才会再次调回来执行try、catch块里的return或throw语句,如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块、catch块里的任何代码。
自动关闭资源的try语句
Java 7增强了try语句的功能——它允许在try关键字后紧跟一对圆括号,可以声明、初始化一个或多个资源,try语句在该语句结束时自动关闭这些资源。
为了保证try语句可以正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口就必须实现close()方法。
2.Checked异常和Runtime异常体系
Checked异常
Checked异常的两种处理方式:
- 当前方法明确知道如何处理该异常,程序使用try...catch块来捕获该异常,然后在对应的catch块中修复该异常
- 当前方法不知道如何处理该异常,应该在定义该方法时声明抛出该异常
使用throws声明抛出异常
使用throws声明抛出异常的思路是:当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果main方法也不知道如何处理这种类型的异常,也可以使用throws声明抛出异常,该异常将交给JVM处理。JVM对异常的处理方法是:打印异常的跟踪栈信息,并中止程序运行,这就是程序在遇到异常后自动结束的原因。
throws可以声明抛出多个异常类,之间以逗号隔开,一旦使用throws语句声明抛出该异常,程序就无须使用try...catch块来捕获该异常了。规则:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或者相同。
使用Checked异常的两大不便
- 对于程序中的Checked异常,Java要求必须显式捕获并处理该异常,或者显式声明抛出该异常,增加了编程复杂度
- 如果在方法中显式声明抛出Checked异常,将会导致方法签名与异常耦合,如果该方法是重写父类的方法,则该方法抛出的异常还会收到被重写方法所抛出异常的限制
所以大部分时候推荐使用Runtime异常
3.使用throw抛出异常
Java允许程序自行抛出异常,用throw语句来完成(throw后面没有s,与throws是有区别的)
throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例,语法如下:
throw ExceptionInstance;
例程:
public class ThrowTest
{
public static void main(String[] args)
{
try
{
//调用声明抛出Checked异常的方法,要么显式捕获该异常,要么在main方法中再次声明抛出
throwChecked(-3);
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
//调用声明抛出Runtime异常的方法既可以显示捕获该异常也可不理会该异常
throwRuntime(3);
}
public static void throwChecked(int a)throws Exception
{
if (a > 0)
{
//自行抛出Exception异常
//该代码必须处于try块里,或处于待throws声明的方法中
throw new Exception("a的值大于0,不符合要求");
}
public static void throwRuntime(int a)
}
public static void throwRuntime(int a)
{
if (a > 0)
{
//自行抛出RuntimeException异常,既可以显式捕获该异常
//也可以完全不理会该异常,把该异常交给该方法调用者处理
throw new RuntimeException("a的值大于0,不符合要求");
}
}
}
自定义异常类
需要提供两个构造器:一个是无参数的构造器,另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(getMessage()方法的返回值
public class AuctionException extends Exception
{
//无参数的构造器
public AuctionException(){}
//带一个字符串参数的构造器
public AuctionException(String msg)
{
super(msg);
}
}
如果需要自定义Runtime异常,只需将AuctionException的Exception基类改为RuntimeException基类。