一、什么是Java异常?
1. Java异常
异常是指程序运行过程中由于外部问题导致的程序异常事件,产生的异常会中断程序的运行。在Java中,异常本身就是一个对象,产生异常就是产生一个异常对象。异常是一个事件,它发生在程序运行期间,中断了正在执行的程序的正常指令流。
2.Java中异常产生的三个原因
- Java 内部错误发生异常,Java 虚拟机产生的异常。
- 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,即运行时异常,在编译期是感知不到的,一般需要在某些类中集中处理这些异常。
- 通过 throw 语句手动生成的异常,这种异常称为受检异常,一般用来告知该方法的调用者一些必要的信息。
3.Java异常体系
在 Java 中所有异常类型都是内置类 java.lang.Throwable 类的子类,即 Throwable 位于异常类层次结构的顶层。Throwable 类下有两个异常分支 Exception 和 Error。
(1)Exception:表示程序可以处理的异常,可以捕获且可能恢复。
- RuntimeException(运行时异常):Error以及RuntimeException以及子类都是非受检异常,这些异常一般是由程序逻辑错误引起的。java编译器在编译时,不会提示和发现这样的异常,出现这类异常时,也会编译通过,对于这些异常,我们应该去修正代码,而不是通过异常去处理。
- CheckedException(受检异常):一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常,即会要求你把这段可能出现异常的程序使用try{}catch{}去捕获或者使用throws在方法后面声明抛出它,否则编译不通过。
(2)Error :表示程序应用程序本身无法克服和恢复的一种严重问题,程序只能瘫痪,例如内存溢出和线程死锁等问题。
二、Java异常处理机制
在 Java 应用程序中,异常处理机制为:抛出异常、捕捉异常。 而异常处理机制主要依赖于try、catch、finally、throw、throws五个关键字
- try:它里面放置可能引发异常的代码。
- catch:后面对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块,可以有多个catch块。
- finally:主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件),异常机制总是保证finally块总是被执行。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者 throw等终止方法的语句,则就不会跳回执行,直接停止。
- throw:用于抛出一个实际的异常,可以单独作为语句使用,抛出一个具体的异常对象。
- throws:用在方法签名中,用于声明该方法可能抛出的异常。
(一)、捕获异常
一般通过try-catch语句或者try-catch-finally语句来实现。
public class TryCatchDemo {
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = "";
System.out.println(str.length());
System.out.println(str.charAt(9));
System.out.println("一切正常");
} catch (NullPointerException e) {
System.out.println("发生了空指针异常");
} catch (StringIndexOutOfBoundsException e) {
System.out.println("字符串索引超出边界异常");
}
System.out.println("程序结束");
}
}
public class TryCatchFinallyDemo {
public static void main(String[] args) {
System.out.println("程序开始");
String str = "";
try {
System.out.println(str.length());
} catch (Exception e) {
System.out.println("出错了");
} finally {
System.out.println("finally中的代码块执行了");
}
System.out.println("程序结束");
}
}
(二)、抛出异常
抛出异常有三种形式:throws、throw、系统自动抛出异常。
public static void main(String[] args) {
String str = "hello offer";
int index = 10;
if (index >= str.length())
//1:使用 throw 在方法内抛出异常
throw new StringIndexOutOfBoundsException();
}else {
str.substring(0,index);
}
}
//2:使用 throws 在方法上抛出异常
int div(int a,int b) throws Exception{
return a/b;
}
三、自定义异常
自定义异常,通常就是定义了一个继承自Exception类的子类,那么这个类就是一个自定义异常类。 使用编写自定义异常类,可分为以下几个步骤:
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。
四、相关面试点
1.throws 和 throw 的区别
-
位置不同。throws是用在方法函数头,后面跟的是异常类,而throw是用在方法体中的,后面跟的是异常对象
-
功能不同。throws是用来声明异常的,让调用者只知道该方法中可能出现的问题,使它的调用者知道使用该方法时需要捕获这个异常,而自己不具体处理。throw是用来抛出具体的问题对象,执行到 throw,功能就已经结束了,跳转到调用者,并将具体的问题对象抛给调用者。
-
性质不同。throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。
2.finally是无条件执行的吗?
不管try块中的代码是否出现异常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return语句,finally块总会被执行。
- 注意事项: 如果在try块或catch块中使用 System.exit(1); 来退出虚拟机,则finally块将失去执行的机会。但是我们在实际的开发中,重来都不会这样做,所以尽管存在这种导致finally块无法执行的可能,也只是一种可能而已。
3.在finally中return会发生什么?
在通常情况下,不要在finally块中使用return、throw等导致方法终止的语句,一旦在finally块中使用了return、throw语句,将会导致try块、catch块中的return、throw语句失效。
- 注意事项: 当Java程序执行try块、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系统立即开始执行finally块。只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块、### final、finally、finalize 有什么区别? catch块里的任何代码。
4.final、finally、finalize 有什么区别?
-
final:是一个修饰符,final修饰的类不能被继承,被final修饰的方法不能被重写,被final修饰的变量初始化之后不能被修改(不一定)。
-
finally:一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码放在方法finally代码块中,前面try{}、catch{}代码块中没有return语句的前提下,该代码块都会执行,一般用来释放资源。
-
finalize:是一个方法,属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
5. 常见的 RuntimeException 有哪些?
- ClassCastException(类转换异常)
- IndexOutOfBoundsException(数组越界)
- NullPointerException(空指针)
- ArrayStoreException(数据存储异常,操作数组时类型不一致)
- 还有IO操作的BufferOverflowException异常
6. Error 和 Exception 区别是什么?
-
Error 类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复;
-
Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。