Java异常类型
所有异常类型都是Throwable的子类,Throwable把异常分成两个不同分支的子类Error和Exception。
Error类型的异常表示运行应用程序中较严重问题。大多数错误表示代码运行时 JVM(Java 虚拟机)出现的问题。
Exception类型是程序本身可以处理的异常,它又分为非运行时异常和运行时异常(RuntimeException即运行期问题)。非运行时异常需要手动添加捕获及处理语句,如果不处理,编译则不通过;运行时异常是jvm正常运行期间抛出的错误,这些异常是不检查异常(编译器不会去检查它),一般由程序逻辑错误所引起,是代码本身有问题,这种问题我们不处理。
如果程序出了问题,并且我们没有做任何处理,最终会被默认处理程序处理,默认处理程序会把异常的信息打印在控制台,同时程序停止运行。
对于所有的可查异常,java规定:方法必须捕捉,如果不捕捉,则必须声明抛出异常
java内置异常类
非检查性异常
ArithmeticException:算数错误。如,一个整数"除以零"
ArrayIndexOutOfBoundsException:数组下标出界。
ArrayStoreException:数组元素赋值类型不兼容
ClassCastException:非法强制转换类型
IllegalArgumentException:向方法传递了一个不合法或不正确的参数
IllegalMonitorStateException:非法监控操作,如等待一个未锁定线程
IllegalStateException:环境应用状态不正确
IllegalThreadStateException:请求操作与当前线程状态不兼容
IndexOutOfBoundsException:某些类型索引超出范围
NegativeArraySizeException:应用程序试图创建大小为负的数组
NullPointerException:当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException:字符串到数字格式的非法转换
SecurityException:由安全管理器抛出的异常,指示存在安全侵犯
StringIndexOutOfBoundsException:索引为负,或者超出字符串的大小
UnsupportedOperationException:遇到不支持请求的操作
检查行异常
ClassNotFoundException:找不到相应的类CloneNotSupportedException:试图克隆一个无法实现 Cloneable 接口的对象
IllegalAccessException:对一个类的访问被拒绝
InstantiationException:试图创建一个抽象接口或抽象类的对象
InterruptedException:一个线程被另一个线程中断
NoSuchFieldException:请求的变量不存在
NoSuchMethodException:请求的方法不存在
try...catch
try/catch关键字可以捕获异常
try{
可能出现问题的代码
}catch(异常名 变量){
针对问题的处理
}
一旦异常被引发,程序控制转到catch块,执行了catch语句后,程序控制从整个try/catch机制的下面一行继续。一个catch语句不能捕获另一个try声明所引发的异常(除非是嵌套的try语句情况)。不能单独使用try。构造catch语句的目的是不中断程序的运行。
try里面定义的属性只能在try块中使用
class Demo{
public static void main(String[] args){
int a,b;
try{
a=5;
b=0;
System.out.println(a/b);
}catch(ArithmeticException e){
System.out.println("Division by zero");
}
System.out.println("After catch exception");
}
}
结果为:Division by zero
After catch exception
某些情况下单个代码可能引起多个异常,处理这种情况可以定义更多的catch子句,每个子句捕获一种类型的异常。
当异常被引发,每一个catch子句被依次检查,匹配上异常类型的子句执行,然后代码从try/catch块后面开始继续。
注意:异常子类必须在它们父类前面(如果不这样,编译器会报错),这是因为运用父类的catch语句将捕获该类型及其所有子类类型的异常。
class Demo{
public static void main(String[] args){
int[] a={1,2};
try{
a[34]=5;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBoundsException catch");
}catch(Exception e){
System.out.println("Exception catch");
}
System.out.println("After catch exception");
}
}
结果为:ArrayIndexOutOfBoundsException catch
After catch exception
try语句可以被嵌套,也就是说一个try语句可以在另一个try语句内部。
建议最好不要嵌套
public class Demo {
public static void main(String[] args) {
try{
int a=args.length;
int b=42/a;
System.out.println("a="+a);
try{
if(a==1)
a=a/(a-a);
if(a==2){
int c[]={1};
c[43]=9;
}
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBounds:"+e);
}
}catch(ArithmeticException e){
System.out.println("Divide by:"+e);
}
}
}
结果:Divide by:java.lang.ArithmeticException: / by zero
如果a=1,则结果为:a=1Divide by:java.lang.ArithmeticException: / by zero如果a=2,则结果为:a=2ArrayIndexOutOfBounds:java.lang.ArrayIndexOutOfBoundsException: 43粗体的try语句嵌套在了外面这个大的try块中,内部的try块不含有处理这个异常的catch语句,它将把异常传给外面的try块,在那里异常被检查是否与之匹配,这个过程将继续直到匹配成功。如果没有catch语句与之匹配,java运行时系统将自动处理这个异常。
finally
finally块无论有没有异常抛出都会执行,所以finally一般用来关闭资源。每个try语句至少,需要一个catch或finally字句。finally块可有可无,不作强制要求。
当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。如果finally语句块中也有return语句,那么直接从finally中返回了,而且finally中的return会使抛出的异常丢失,所以不建议在finally中ruturn.。finally中抛出的异常会覆盖catch中抛出的异常。
在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
public class Demo {
public static void main(String[] args) {
int[] a={1,2};
try{
a[34]=5;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception catch");
}finally{
System.out.println("finally");
}
}
}
结果为:Exception catch
finally
throw
有时候有些错误在jvm看来不是错误,系统就不会抛出异常(如输入的年龄小于0),这时候我们需要手动引发异常。程序可以用throw语句抛出一个明确的异常。程序在throw语句之后立即停止,后面的任何语句不被执行,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块
异常是异常类的实例对象,我们可以创建异常类的实例对象通过throw语句抛出
用法:throw 异常对象;
有两种获得异常对象的方法:在catch子句中捕获到的异常对象或者用new操作符创建
public class Demo {static void demo(){try{
throw new ArithmeticException("demo");//新实例化的异常对象
}catch(ArithmeticException e){
System.out.println("Caught inside demo");
throw e; //捕获到的异常对象e
}
}
public static void main(String[] args) {
try{
demo();
}catch(ArithmeticException e){
System.out.println("Caught"+e);
}
}
}结果为:Caught inside demoCaughtjava.lang.ArithmeticException:demo注意:throw new ArithmeticException();中new用来构造ArithmeticException实例。所有java内置的运行异常有两个构造方法:一个没有参数,一个带有一个字符串参数。当用第二种形式时,参数描述指定异常的字符串(抛出异常的原因),如果对象用作print()或println()输出时,该字符串被显示(打印异常原因)。
throw是语句抛出异常。它不可以单独使用,要么与try…catch配套使用,要么与throws配套使用。
throws
throws 是方法抛出异常,在一个方法中可能出现了某些异常,我们没法去处理它,然后就将这个异常向上抛出。如果一个方法中没有捕获某个检查性异常的语句,则该方法必须使用 throws 关键字来声明,异常的处理则交由它的调用者。throws 关键字放在方法声明的尾部。例如汽车出现了故障时,汽车不会自己去处理这个异常,而是交给开车的人来处理。
如果一个方法声明了throws,然后方法里面有try...catch块,直接catch异常的引用不再throws(即上层调用者不会去处理这个异常)。
Throws抛出异常的规则:
1) 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误
3)当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出。
4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
public class Demo {
public static void test() throws ArithmeticException {
throw new ArithmeticException();
}
public static void main(String[] args) {
try{
test();
}catch(ArithmeticException e){
System.out.println("Caught:"+e);
}
}
}
结果为:Caught:java.lang.ArithmeticException: / by zero
在test()后面声明throws来引发ArithmeticException异常,在main方法中必须定义一个try/catch语句来捕获该异常
通过throw抛出异常后,如果想在上一级代码中捕获并处理异常,需要在抛出异常方法中使用throws关键字在方法声明中指明要跑出的异常。如果要捕获throw抛出的异常,必须使用try/catch语句
自定义异常
系统中有些错误是符合Java语法的,但不符合逻辑,此时就可以自定义异常。如果异常中没有我们想要的异常,也剋有自定义一个异常。比如人的性别是中性时需要抛出异常,但是一直异常中没有这个异常,这时候我们可以自定义一个异常抛出。
在 Java 中可以自定义异常。所有异常都必须是 Throwable 的子类。如果希望写一个检查性异常类,则需要继承 Exception 类。如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
一般情况下我们都会直接继承Exception类
Exception类没有定义任何方法,它继承了Throwable提供的一些方法。
Throwable 类的主要方法:
String getMessage():返回关于发生的异常的详细信息Throwable getCause():返回一个Throwable 对象代表异常原因
String toString():使用getMessage()的结果返回类的串级名字
void printStackTrace():打印toString()结果和栈层次到System.err,即错误输出流。
StackTraceElement [] getStackTrace():返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
Throwable fillInStackTrace():用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。
Java自定义异常的使用要经历如下四个步骤:
1、定义一个类继承Throwable或其子类。
2、添加构造方法(当然也可以不用添加,使用默认构造方法)。
3、在某个方法类抛出该异常。
4、捕捉该异常。
public class MyException extends Exception { //自定义的MyException异常
}
public class Demo {
static void compute(int a) throws MyException{
System.out.println("Called compute("+a+")");
if(a>10)
throw new MyException();
System.out.println("Normal exit");
}
public static void main(String[] args) {
try{
compute(1);
compute(20);
}catch(MyException e){
System.out.println("Caught:"+e);
}
}
}
结果为:Called compute(1)
Normal exit
Called compute(20)
Caught:com.DE.MyException