1.异常的概念
异常是在程序运行时发生的一些意外情况,如硬件故障、输入错误、网络连接中断等,这些情况都会导致程序无法按照正常流程执行下去。当程序遇到异常情况时,会抛出一个异常对象,该异常对象描述了异常情况的类型和详细信息。通常情况下,程序会停止执行当前任务,并尝试捕获并处理异常,以确保程序能够正常运行。
异常处理是一种编程技术,用于在程序运行时检测和处理异常情况。它包括捕获异常、处理异常、记录异常信息、重新抛出异常等步骤。通过使用异常处理技术,可以使程序更加健壮和可靠,提高程序的容错能力。
2.异常的结构
- Throwable:是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception
- Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等
- Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。我们平时所说的异常就是Exception。其下面有许多的子类异常,例如:受检查异常(Checked Exception),运行时异常(RunTimeException),这些异常也是最主要介绍的异常。
3.异常的分类
3.1 受检查异常(Checked Exception)
这种异常发生在编译阶段,所以也叫做编译异常,这种异常编译器会进行提醒。
受检查异常通常是由于外部环境的因素所导致的,例如文件操作中遇到的I/O错误、数据库操作中遇到的连接中断等等。对于这些异常,程序员需要决定如何处理它们,通常可以选择进行异常处理、重试操作或者向用户报告错误信息。如果不对受检查异常进行处理,程序将无法通过编译。
3.2 运行时异常(RunTime Exception)
在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常(Unchecked Exception) 。
运行异常分为:数组越界(ArrayIndexOutOfBoundsException),空指针引用(NullPionterException),类型转换,算术操作溢出(ArithmeticException)等。
4.捕获异常
4.1 try块
1. try{ 2. //Code that might generate exceptions 3. }
如果方法中产生了异常,那么这个方法将抛出异常结束。而在try关键字后的普通代码块中编写可能产生异常的代码块,这个块将“尝试”各种可能产生异常的方法的调用,这样当抛出异常的时候将不会立即结束。
4.2 catch捕获
try{ //Code that might generate exceptions } catch(Type1 e1){ //handle exception of Type1 } catch(Type2 e2){ //handle exception of Type2 } //etc...
try块中产生的异常将被相对应的第一个catch子句(异常处理程序)捕获,然后执行catch子句中的语句,当catch子句执行结束,则处理程序的查找过程结束。
5. 创建自定义异常
虽然Java中提供有很多异常,但是并不能包括所有的异常,所以我们可以自己定义异常。
建立新的异常,必须继承已有的异常类继承,最好选择相似的异常类继承。
代码如下:
//Creating your own exceptions. public class MyException extends RuntimeException{ public MyException() { super(); } public MyException(String message) { super(message); } } public class TestException { public static void main(String[] args) { try{ f(); }catch (MyException e){ e.printStackTrace(); } try{ g(); }catch(MyException e){ e.printStackTrace(); } } private static void f() throws MyException{ System.out.println("Throwing MyException from f()"); throw new MyException(); } private static void g() throws MyException{ System.out.println("Throwing MyException from g()"); throw new MyException("originated in g()"); } } /*OutPut: Throwing MyException from f() MyException at TestException.f(TestException.java:25) at TestException.main(TestException.java:12) Throwing MyException from g() MyException: originated in g() at TestException.g(TestException.java:30) at TestException.main(TestException.java:17) */
6. finally
有一些代码,无论try块中的异常是否抛出 ,都希望它可以执行。所以引用了finally子句,无论异常是否抛出,finally子句总能被执行。
对于没有垃圾回收和析构函数自动调用的机制的语言来说,finally非常重要。它可以使不论try语句中发生了什么,内存总能释放。但Java中有垃圾回收机制,finally有什么作用呢?答:它可以使内存之外的资源恢复到初始状态。
格式:
try{ //Code that might generate exceptions //that might throw A,B,or C } catch(Type1 A){ //handle exception of Type1 } catch(Type2 B){ //handle exception of Type2 } catch(Type3 C){ //handle exception of Type3 } finally{ //Activities that happen every time }
验证finally子句是否执行,只需将5.代码加上下列代码,就可验证有异常抛出:
1. finally{ 2. System.out.println("finally"); 3. } 4. /*OutPut 5. finally 6. */
无异常抛出:
public static void main(String[] args) { try{ System.out.println("Normal"); }catch(RuntimeException e){ e.printStackTrace(); }finally{ System.out.println("finally"); } } /*OutPut Normal finally */
7. 一些注意点
- .throw必须写在方法体内部
- 抛出的对象必须是Exception 或者 Exception 的子类对象
- 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
- 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
- throws 必须跟在方法的参数列表之后
声明的异常必须是 Exception 或者 Exception 的子类
方法内部如果抛出了多个异常, throws 之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可