1 什么是java异常
异常是指在程序运行时,阻碍程序正常执行的错误事件。比如:用户输入错误数据、硬件故障、网络阻塞等都会导致出现异常。 只要产生了异常,一个异常对象就会被创建,JRE就会试图寻找异常处理程序来处理异常。
2 Java异常层级
![](https://i-blog.csdnimg.cn/blog_migrate/3e1232fdd72d45554de5dc31df5c5cd9.png)
- Throwable是所有异常的父类,它有两个直接子对象Error,Exception;
- Error :运行时错误;Error对象由JVM生成并抛出,大多数错误与开发者无关,所以开发者也不用处理;如:OutOfMemoryError(内存溢出错误)、NoClassDefFoundError(类定义错误)、LinkageError(链接错误)等;
Exception分为检查型异常和非检查型异常:
- 检查型异常:所谓检查(Checked)是指编译器必须检查这类异常,检查的目的一方面是因为该类异常的发生难以避免,另一方面就是让开发者去解决掉这类异常,所以称为必须处理(try …catch)的异常。如果不处理这类异常,集成开发环境中的编译器一般会给出错误提示。
例如:一个读取文件的方法代码逻辑没有错误,但程序运行时可能会因为文件找不到而抛出FileNotFoundException,如果不处理这些异常,程序将来肯定会出错。所以编译器会提示你要去捕获并处理这种可能发生的异常,不处理就不能通过编译.
![](https://i-blog.csdnimg.cn/blog_migrate/be16adfc912a7d9137d75f1a894bb7c7.png)
- 非检查型异常:所谓非检查(Unchecked)是指编译器不会检查这类异常,不检查的话则开发者在代码的编辑编译阶段就不是必须处理,这类异常一般可以避免,因此无需处理(try …catch)。如果不处理这类异常,集成开发环境中的编译器也不会给出错误提示。RuntimeException都属于Unchecked。
例如:你的程序逻辑本身有问题,比如数组越界、访问null对象,这种错误你自己是可以避免的。编译器不会强制你检查这种异常。
![](https://i-blog.csdnimg.cn/blog_migrate/01181201256eb789c003bd3043c02d04.png)
3 异常方法
下面的方法都是Throwable的主要方法:
方法 | 说明 |
---|---|
public String getMessage() | 返回异常信息 |
public Throwable getCause() | 返回产生异常的原因 |
public void printStackTrace() | 打印栈轨迹信息到标准错误流 |
4 异常处理
4.1 捕获异常try catch
try
{
// 保护代码:可能有异常的代码
}catch(ExceptionName e1)
{
//Catch 块
}
4.2 多重catch
try{
// 保护代码:可能有异常的代码
}catch(ExceptionType1 e1){
// 程序代码
}catch(ExceptionType2 e2){
// 程序代码
}catch(ExceptionType3 e2){
// 程序代码
}
- 如果保护代码发生异常,异常被抛给第一个 catch 块;如果抛出异常的类型与 ExceptionType1匹配,它在这里就会被捕获,不会继续向下传递;如果不匹配,它会被传递给第二个 catch 块;如此,直到异常被捕获或者通过所有的 catch 块。
- 范围小的异常类(子类)在上面,范围大的异常类(父类)在下面;
- 尽量不要用try-catch嵌套,结构差;
- 一个catch子句中可以捕获多个异常,但是并列的异常类型不能具有继承关系;
catch(IOException | SQLException e)
4.3 throws/throw
-
throws在方法的签名处声明此方法可能抛出异常;
-
如果一个方法存在可能有异常的代码,要进行异常处理,要么对可能有异常的代码try-catch,要么 throws给其调用者处理;
-
可以使用 throw关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
5 finally
try{
// 保护代码:可能有异常的代码
}catch(Exception e){
// 异常处理
}finally{
// 可有可无,finally代码块一定会被执行,进行一些清理类型的收尾善后工作
}
6 自定义异常
- 通过继承Exception类或其子类来实现自定义异常类;
//自定义异常类:分数越界异常
public class OutOfScoreBoundException extends Exception{
public OutOfScoreBoundException(String message) {
super(message);
}
public OutOfScoreBoundException() {
super();
}
}
public class ExceptionDemo {
public static boolean isScoreLegal(int score) throws Exception {//也可以throws OutOfScoreBoundException
if(score>150||score<0){
//抛出自定义异常,下面两种方式都可以
// throw new Exception("Your score is out of bound");
throw new OutOfScoreBoundException("Your score is out of bound !");
}else {
return true;
}
}
public static void main(String[] args) {//并列catch的Exception类型由小到大
Scanner scanner=new Scanner(System.in);
int score=scanner.nextInt();
try {
if (isScoreLegal(score)){
System.out.println("Your score is legal !");
}
} catch (OutOfScoreBoundException e){
e.printStackTrace();
System.out.println("---->OutOfScoreBoundException");
} catch (Exception e) {
e.printStackTrace();
System.out.println("---->Exception");
}
}
}
160
---->OutOfScoreBoundException
OutOfScoreBoundException: Your score is out of bound !
at ExceptionDemo.isScoreLegal(ExceptionDemo.java:13)
at ExceptionDemo.main(ExceptionDemo.java:23)
7 常见相关面试题
(1)检查型异常和非检查型异常的区别?
- 检查型异常:编译器必须检查的异常,此类异常难以避免;开发者必须处理(try-catch),如果不处理,编译器会有错误提示;
- 非检查型异常:编译器不用检查的异常,此类异常可以避免也必须避免;开发者不用处理(try-catch);
(2)throws/throw有什么区别?
- throws在方法的签名处声明此方法可能抛出异常;
- 可以使用 throw关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
(3) main方法抛出异常时发生了什么?
- 当main方法抛出异常时,Java运行终止并在控制台打印异常信息和栈轨迹。
8 参考博客
https://www.runoob.com/java/java-exceptions.html
http://www.importnew.com/7383.html