1 异常分类
- Throwable
- Error
- 表示 JVM 无法处理的错误,如 OutOfMemoryError, StackOverflowError。
- Exception
- 未检查异常(RuntimeException,运行时异常)
- 程序出错导致的异常,例如 NullPointerException,IllegalArgumentException,ArrayIndexOutOfBoundsException
- 已检查异常(非 RuntimeException,非运行时异常)
- 所有继承自 Exception,而不继承自 RuntimeException 类的异常
- 外部错误,例如 IOException,FileNotFoundException
- 在编译期间检查,必须提供异常处理器。
- 未检查异常(RuntimeException,运行时异常)
- Error
2 声明异常
已检查异常
需要声明,或被捕获。如有多个需要在方法首部列出所有,逗号隔开。
Errors 和 未检查异常
不需要声明。因为这类错误本身就是 bug,应该被修复,出现此类错误时程序就应该立即停止执行。
3 抛出异常
throw new Exception();
4 自定义异常
- 创建一个派生于 Exception 的类 ,或者派生于 Exception 子类的类。
- 一般需要定义两个构造器,一个是默认的,另一个是带有详细描述信息的构造器
class FileFormatException extends IOException
{
public FileFormatException() {}
public FileFormatException(String gripe){
super(gripe);
}
}
5 捕获异常
- 如果异常没有被捕获,程序将会停止运行
- try/catch 捕获异常
- 如不捕获异常,可 throws 声明异常,将异常传递给调用者
- 子类覆盖超类的方法中,只能 throws 超类方法的异常,其他只能自己捕获处理
5.1 捕获多个异常
1)基本语句
try{
}catch (FileNotFoundException e){
}catch (UnknownHostException e){
}
2)合并catch语句
try{
}catch (FileNotFoundException | UnknownHostException e){
}
5.2 再次抛出异常
1)基本方法
try{
}catch (SQLException e){
throw new ServletException("database error: "+e.getMessage());
}
2)保留原始异常
try{
}catch (SQLException e){
Throwable se=new ServletException("database error");
se.initCause(e);
throw se;
}
3)获取原始异常
Throwable e = se.getCause();
5.3 finally 子句
1)基本语法
try{
}catch(Exception e){
}finally{
in.close();
}
2)建议使用
强烈建议独立使用 try/catch 和 try/finally 语句块,提高代码的清晰度。
InputStream in= ... ;
try{
try{
code that might throw exceptions
}finally{
in.close();
}
}catch(IOException e){
show error message
}
- 注意:当 finally 和 catch 包含 return 语句,会执行 finally 的 return。
- 注意:finally 也可能抛出异常,而导致本来要 catch 抛出的异常被覆盖
5.4 带资源的 try 语句
1)基本语法
假如资源实现了 AutoCloseable/Closeable 接口。可以利用带资源的 try 语句,try 退出时,会自动调用 res.close()。
try(Resource res=...){
work with res
}
2)指定多个资源
try (Resource res1=...,Resource res2=...){
work with res
}
如果 .close() 也抛出了异常,不会覆盖原来该抛出的异常,而是被抑制,可以通过 getSuppressed 方法获取被抑制的异常。
5.5 分析堆栈跟踪
堆栈跟踪(stack trace)是一个方法调用过程的列表。
1)getStackTrace()
得到 StackTraceElement 对象的一个数组。
能获得文件名,类名,当前执行的代码行号
Throwable t = new Throwable();
StackTraceElement[] frames = t.getStackTrace();
for(StackTraceElement f : frames)
System.out.println(f);
2)Thread.getAllStackTrace
获得所有线程的堆栈跟踪
Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
for(Thread t : map.keySet())
{
StackTraceElement[] frames=map.get(t);
for(StackTraceElement f : frames)
System.out.println(f);
}