一说谈到异常,可能就有小伙伴说,这个啊,我 try...catch...finally用得贼溜。别急哈,后面有个 案例,看完以后你确定会以为本身对异常的理解也不是那么透彻了,同时本文还可能会扫到你的一些知识盲点。额,扯远了~程序员
异常通常指不期而至的各类情况,如:文件不存在、空指针、非法参数等。
异常是一个事件,发生在程序运行期间,干扰了正常的指令流程。
Java 中使用 Throwable 类及其子类来描述各类不一样的异常。所以,Java 异常都是对象,是 Throwable 的子类实例,描述了出如今一段编码中的错误条件。当条件生成时,错误将引起异常。数据库
Java 异常类层次结构图:编程
从图上咱们能够看到,Java 异常都继承自 Throwable,Throwable 分为两大派系,一类是 Error(错误),一类是 Exception(异常)。数组
Error 是程序员没法处理的错误
,表示运行应用程序中教严重的问题。大多数错误与代码编写者执行的操做无关,而表示代码运行时 JVM 出现的问题。好比,Java 虚拟机运行时错误(VirtualMachineError),当 JVM 再也不有继续执行操做所需的内存资源时,将出现 OutOfMemoryError。这时异常发生时,Java 虚拟机通常会终止线程。安全
因此这一类异常咱们通常不用太纠结。bash
这是程序自己能够处理的异常。
Exception 有一个很是重要的子类 RuntimeException,RuntimeException 类及其子类表示 JVM 经常使用操做引起的错误,例如空值对象引用、除数为零、数组角标越界则分别会引起 NullPointException、ArithmeticException、ArrayIndexOutOfBoundException。学习
敲黑板!!分清异常和错误的区别,异常是能够被程序自己处理的,错误不能。ui
又称编译时异常,是编译器要求必须处置的异常。
正确的程序在运行中,很容易出现的、情理可容的异常情况。可查异常虽然是异常情况,但在必定程度上它的发生是能够预计的,并且一旦发生这种异常情况,就必须采起某种方式进行处理。编码
除了RuntimeException及其子类之外,其余的Exception类及其子类都属于可查异常。这种异常的特色是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,不然编译不会经过。spa
编译器不要求强制处置的异常,包括运行时异常(RuntimeException)和错误(Error)。
都是 RuntimeException 类及其子类。
这些异常是不检查异常
,程序中能够选择捕获处理,也能够不处理。这些异常通常是由程序逻辑错误引发的,程序应该从逻辑角度尽量避免这类异常的发生。
是RuntimeException之外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,若是不处理,程序就不能编译经过。
遇到异常怎么办?要么本身想办法处理,要么就抛给别人。
抛出异常:
当一个方法出现错误引起异常时,方法建立异常对象并交付给运行时系统,系统对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
捕获异常:
在方法抛出异常以后,运行时系统将转为寻找合适的异常处理器(Exception handler)。潜在的异常处理是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有异常处理器的方法并执行。当运行时系统遍历了调用栈都没找到合适的异常处理器,则运行时系统终止,Java 程序终止。
对于运行时异常、错误和可查异常,Java 要求的异常处理方式有所不一样。
可以捕捉异常的方法,须要提供相符类型的异常处理器。也就是说,一个方法所能捕获的异常,一点是 Java 代码在某处所抛出的异常
。
任何Java代码均可以抛出异常,如:本身编写的代码、来自Java开发环境包中代码,或者Java运行时系统。不管是谁,均可以经过Java的throw语句抛出异常。
从方法中抛出的任何异常都必须使用throws子句。
捕捉异常经过try-catch语句或者try-catch-finally语句实现。
总结来书。Java 规定:对于可查异常必须捕捉、或者声明抛出。运行忽略不可查的 RuntimeException 和 Error。
基本语法以下:
try {
// 可能会发生异常的程序代码
} catch (Type1 id1){
// 捕获并处置try抛出的异常类型Type1
} catch (Type2 id2){
//捕获并处置try抛出的异常类型Type2
}复制代码
关键词 try 后面的大括号区域为可能发生异常的代码,称为监控区。当抛出异常或者出现运行时异常,而后由 Java 运行时系统巡展匹配 catch 子句。如有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。
匹配规则:抛出的异常属于 catch 语句捕获异常类及子类,则匹配成功。
须要注意的是:一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其余的catch子句再也不有匹配和捕获异常类型的机会,而且 try 里面若是有没有走完的语句也会自动跳过。
这个很简单,不管 try-catch 是正常结束仍是发生异常捕获,都会执行 finally 语句,若是在 finally 以前发生了 return,那么 finally 语句块会在 retrun 以前执行。
小结:
try 块:用于捕获异常。其后可接零个或多个catch块,若是没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:不管是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回以前被执行。
finally 若是有 return 会覆盖 catch 里的throw,一样若是 finally 里有 throw 会覆盖 catch 里的 return。
try-catch-finally 规则
1.必须在 try 后面添加 catch 或 finally。能够同时存在,catch 块也能够有多个,可是 catch 必须放在 try 块或者 catch 块后面。
2.try-catch-finally 能够嵌套
3.在 try-catch-finally 结构中,能够从新抛出异常
4.除非 finally 中抛出异常或者 JVM 中止运行,不然都会执行 finally 语句
try-catch-finally 语句执行顺序
1.当 try 没有捕获到异常时:try 语句正常执行,程序跳过 catch 语句,执行 finally。
2.当 try 捕获到异常时,catch 没有匹配上异常,则交个 JVM 处理,finally 语句块仍是会被执行,可是 finally 以后的语句不会被执行了。
3.当 try 捕获到异常,catch 匹配上了,则按照 try-catch-finally 的正常顺序执行,可是 try 里面异常语句以后的语句不会被执行。
任何 Java 代码均可以抛出异常,语句经过 throw 抛出、方法则是 throws。
为何要 throw 异常?
若是一个方法可能会出现异常,可是没有能力处理这种又一次,则能够在方法声明处用 throws 语句来抛出。
throws 语句能够同时声明抛出多个异常,语法格式以下
void methodName()throws Exception1,Exception2,Exception3{
}复制代码
就酱紫。此时这个方法就不用对方法重点问这些异常作任何处理,可是调用这个方法的语句必需要处理,要么继续抛,要么 try-catch。
Throws 抛出规则
1.若是是不可查异常,那么不用声明,编译仍然能够经过,可是运行时会被JVM 抛出
2.若是是可查异常,要么 try-catch,要么 throws,不然编译没法经过。
3.当抛出了异常时,该方法的调用者才会处理或者从新抛出该异常。
4.调用 throws 异常的方法,必须 try-catch 调用语气,且 catch 的异常必须是抛出异常的同类或者父类。
Throw 抛出异常
这个真没什么好说的了,想抛或者须要抛,就直接调用就好了,注意 throw 后面只能接 Throwable 的子类。
这个本应该在开篇就讲的,可是好像都不怎么经常使用,因此就放在这里查漏补缺吧
返回值 | 方法名 | 方法说明 |
---|---|---|
Throwable | fillInStackTrace() | 在异常堆栈跟踪中填充 |
Throwable | getCause | 返回 Throwable 的 cause |
String | getLocalizedMessage | 建立此 Throwable 的本地化描述 |
String | getMessage | 返回此 Throwable 的详细消息字符串 |
StackTraceElement[] | getStackTrace() | 提供编程访问由printStackTrace 输出的堆栈跟踪信息 |
Throwable | initCause | 将此 throwable 的 cause 初始化为指定值 |
void | printStackTrace | 将此 Throwable 及其追踪输出至标准错物流 |
String | toString | 返回此 Throwable 的简短描述 |
运行时异常
1.ArrayIndexOutOfBoundException
数组索引越界异常。
2.ArithmeticException
算术条件异常,如除数为0
3.NullPointException
空指针异常。
4.ClassNotFoundException
找不到类异常。
5.NegativeArraySizeException
数组长度为负异常
6.ArrayStoreException
数组中包含不兼容的值抛出异常
7.SecurityException
安全性异常
8.IllegalArgumentException
非法参数异常
IOException
1.IOException
操做输入流和输出流可能出现的异常
2.EOFException
文件已结束异常
3.FileNotFoundException
文件未找到异常
使用Java 内置的异常类能够描述在编程中出现的大部分状况,除此以外,用户还能够自定义异常。自定义异常类,只须要继承 Exception 便可。
在程序中使用自定义异常类,大致可分为如下几个步骤。
1.建立自定义异常类。
2.在方法中经过throw关键字抛出异常对象。
3.若是在当前抛出异常的方法中处理异常,可使用try-catch语句捕获并处理;不然在方法的声明处经过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操做。
4.在出现异常方法的调用者中捕获并处理异常。
异常差很少就到这里吧,作完这个小练习,若是能作对的话就差很少了,若是作不对,那再回过头去从新读一遍这篇文章。
//执行语句
TestException testException1 = new TestException();
try {
testException1.testEx();
} catch (Exception e) {
e.printStackTrace();
}
//异常类
public class TestException {
public TestException() {
}
boolean testEx() throws Exception {
boolean ret = true;
try {
ret = testEx1();
} catch (Exception e) {
Log.e("sss___sss","testEx, catch exception");
ret = false;
throw e;
} finally {
Log.e("sss___sss","testEx, finally; return value=" + ret);
return ret;
}
}
boolean testEx1() throws Exception {
boolean ret = true;
try {
ret = testEx2();
if (!ret) {
return false;
}
Log.e("sss___sss","testEx1, at the end of try");
return ret;
} catch (Exception e) {
Log.e("sss___sss","testEx1, catch exception");
ret = false;
throw e;
} finally {
Log.e("sss___sss","testEx1, finally; return value=" + ret);
return ret;
}
}
boolean testEx2() throws Exception {
boolean ret = true;
try {
int b = 12;
int c;
for (int i = 2; i >= -2; i--) {
c = b / i;
Log.e("sss___sss","i=" + i);
}
return true;
} catch (Exception e) {
Log.e("sss___sss","testEx2, catch exception");
ret = false;
throw e;
} finally {
Log.e("sss___sss","testEx2, finally; return value=" + ret);
return ret;
}
}
}复制代码
求以上语句的答应结果~
本身先读一遍,再来对答案哦~
sss___sss: i=2
sss___sss: i=1
sss___sss: testEx2, catch exception
sss___sss: testEx2, finally; return value=false
sss___sss: testEx1, finally; return value=false
sss___sss: testEx, finally; return value=false复制代码
好了,异常机制的学习就到这里吧。