java的异常处理机制(入门篇)
文章目录
异常处理机制的概述
错误与异常
错误
- 程序进入了死循环或内存溢出,这类现象称为错误。错误只能在编程阶段解决,运行时程序本身无法解决,只能依靠其他程序干预,否则会一直处于一种不正常的状态。
异常
-
就是程序运行过程中发生了无法预判的结果,当异常发生的时候,异常 被抛出,导致程序停止。
-
当java程序违反了java语言的语义规则时,Java虚拟机就会发出出错的信号。
官方源码解释: (1)异常类Exception(extends Throwable),是从JDK1.0版本开始就已经有了, 类异常及其子类 是Throwable的一种形式,表示合理的应用程序可能希望捕获的条件。 (2) 类异常和任何不属于RuntimeException子类的子类都是检查异常。如果方法或 构造函数的执行可以抛出选中的异常并在方法或构造函数边界之外传播,则需要在 方法或构造函数的throws子句中声明选中的异常。
异常类的层次结构
结构图:
Exception异常类的子类
(1)RuntimeException——运行时异常类
主要包括以下异常子类
- ArithmeticException 算数异常类:表示遇到异常的算数问题,如被0整除。
- ArrayIndexOutBoundsException 数组下标越界异常类:当索引值为负或者大于数组长度时,会出现用非法索引访问数组时抛出的异常。
- ArrayStoreException 数组元素类型不匹配异常类:试图把与数组类型不相符的值存入数组。
- NumberFormatException 数字格式化异常:试图把字符串转换成数值类型不能运行时,则会抛出该异常类。
- ClassCastException 类型强制转换异常类:试图把一个对象的引用强制转换为不适合的类型
- IndexOutOfBoundsexception 下标越界异常类:下标越界。
- NullPointerException 空指针异常类:试图使用一个空的对象引用。
- SecurityException 违背安全原则异常类:检测到了违反安全的行为。
(2)NoSuchMethodException——方法未找到异常类
(3)java.awt.AWTException——图形界面异常类
(4)java.io.IOException——输入输出异常类
-
IOException:申请I/O操作没有正常完成
-
EOFException:在输入操作正常结束前遇到了文件结束符。
-
FileNotFoundException:在文件系统中,没有找到由文件名字字符串指定的文件。
(5)Exception异常类的其他子类 -
EmptyStackException:试图访问一个空堆栈中的元素
-
NoSuchFieldException:试图访问一个不存在的域
-
NoSuchMethodException:试图访问一个不存在的方法
-
ClassNotFoundException:具有指定名字的类或者接口没有被发现
-
CloneNotSupportedException:克隆一个没有实现Cloneable接口的类
-
IllagalAccessException:试图用给出了完整的路径信息的字符串加载一个类。但当前正在执行的方法无法访问指定类,因为该类不是public类型或在另一个包中
-
InstantiationException:试图使用Class的newInstance方法创建一个对象实例,但指定的对象没有被实例化,因为它是一个接口、抽象类或者一个数组
-
InterruptedException:当前的线程正在等待,而另一个线程使用了Thread的interrupt()方法中断了当前线程
Error类的子类
(1)VirtualMachineError——虚拟机错误类
- OutOfMenoryError:内存溢出错误
- StackOverflowError:栈溢出错误
(2)LinkageError——链接错误类
(3)NoClassDefNotFoundError——类定义未找到错误类
(4)java.awt.AWTError——图形界面错误类
异常的处理
异常发生的原因
(1)java虚拟机检测到了非正常的执行状态,这些状态可能有以下几种情况引起的
1)表达式计算违反了java 语言的语义,例如整数被0除;
2)载入或链接java程序时出错;
3)超出了某些资源限制,例如使用的太多内存或者超出数组的长度。
(2)java程序代码中的throw语句被执行。
(3)异步异常发生;原因可能是Thread的stop()方法被调用与java虚拟机内部发生错误。
如何处理异常
(1)抛出异常
在程序运行时当语义规则被违反时,将会抛出(throw)异常,即产生一个异常事件,
生成一个异常对象。一个异常对象可以由java虚拟机来产生,也就是由运行的方法生成。
异常对象中包含了异常事件类型、程序运行状态等必要信息。
(2)捕获异常
异常抛出后,异常对象被提交到运行系统,系统将从生成异常对象的代码开始,沿方法的调用栈
进行查找,直到找到包含相应处理的方法代码,并把异常对象交给该方法进行处理,这个过程称
为捕获异常
try…catch…finally子句
说明:
在程序设计时,把可能会发生异常的代码放在try语句段中,利用try语句对这组代码进行监视,如
果发生问题,系统就会抛出异常对象e,交给catch语句处理,处理步骤如下:
1) catch语句执行之前,先要识别抛出的异常对象类型catch能否捕获,如果catch语句参数中声明的
异常类与抛出的异常类相同,或者是它的父类,catch语句就能捕获这种异常
2)如果发生的异常没有捕获到,即抛出的异常对象e与catch定义的“异常类型”不匹配,流程控制将
沿着调用堆栈一直向下传。也就是说catch方法1不能处理异常的话,就把异常传给catch方法2,如
果catch方法2 不能处理异常,再把异常传给方法3,这样把异常传到能够处理它的方法,像这样一
个try代码块后面跟随多个catch代码块的情况叫多重捕获。
3)如果知道最后还是没有发现处理异常的catch语句,那么在finally子句执行完后,调用ThreadGroup
的unCatchException方法,终止当前的线程(即发生了异常的线程)。
public static void method01(){
Scanner sc=new Scanner(System.in);
try {
int a= sc.nextInt(), b= sc.nextInt();
int c=a/b;
int arr[]={1};
arr[0]=c;
//发生空指针异常
String str=null;
System.out.println(str.replace('c','a'));
System.out.println(a+"/"+b+"="+c);
}catch (ArithmeticException e){//异常捕捉,算术异常
System.out.println("除法运算,除数不能为0");
}catch (InputMismatchException e){
System.out.println("输入数据类型错误");
System.out.println("请重新输入");
method01();
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("下标溢出");
}catch (Exception e){//无法判断捕捉到什么异常
e.printStackTrace(); //TODO 测试时才用,打印异常
System.out.println("发生了异常,信息:"+e.toString());
return;//TODO
}finally {//有没有发生异常,都会运行,return也阻止不了
System.out.println("不管发生有没有发生异常,这里一定运行");
}
}
throw语句
在catch子句中异常对象是java运行时系统抛出的,抛出的异常对象也可以通过程序代码来实现。使用
throw语句就可以明确地抛出一个异常对象,throw是一个java语言的关键字,用来告知编译器此处要发
生一个异常,throw后面要跟一个新创建的异常类对象,用于指出异常的名称和类型。
语句格式:
<throw><new><异常对象名()>
说明:
程序执行中会throw语句处终止,转向try...catch寻找异常处理方法,不再执行throw后面的语句。
public class Test03 {
public static void main(String[] args) {
try {
method01();
}catch (NullPointerException e){
System.out.println("再次捕获一个:" + e);
}
}
public static void method01(){
try {
throw new NullPointerException("空指针异常");
}catch (NullPointerException e){
System.out.println("\n在method方法中捕获一个" + e);
throw e;
}
}
}
throws子句
throws用来声明一个方法中可能抛出的各种异常,并说明该方法会抛出异常但不会捕获异常
1)抛出异常交由其他方法处理
2) 多个异常的声明
一个方法可以声明抛出多个异常,在多个异常之间用逗号隔开
3)有方法抛出异常交友系统处理
格式:
<返回值类型><方法名><([参数])><throws><异常类型>{ }
//自定义异常自己是不能处理的,只能进行抛出
public static void method03 (String sex)throws Exception{
//当sex不是男的也不是女的,就认为发生异常
if(!(sex.equals("男")||sex.equals("女"))){
throw new Exception("性别不男不女");
}
}
public static void method04(String sex)throws SexException{
if(!(sex.equals("男")||sex.equals("女"))){
throw new SexException("性别不男不女");
}
}
class SexException extends Exception{
public SexException(String msg) {
super(msg);
}
}
finally语句
无论是否发生异常,finally语句都会被执行
编译时对异常的检查情况
1)可检测类和不可检测类
不可检测的异常类是RuntimeException及其子类,Error及其子类,其他的异常类则是可检测的类。
2)可检测异常的处理
通过try...catch去捕获,或者通过throws抛出交由调用者处理
3)不可检测异常(运行时异常类)的处理
编译器对不可检测的异常不进行检测,解释器在执行程序时会对出现异常的程序给出异常报告
自己创建异常类
自定义异常类
自定义异常类型是从Exception类中派生的,可以通过继承的方式来创建
格式:
<class><自定义异常名><extends><Exception>{...}
注意:
1) 所有异常都必须是Throwable的子类
2)如果是检查性异常类,则继承Exception
3) 如果是一个运行时异常类,则继承RuntimeException类
class SexException extends Exception{
public SexException(String msg) {
super(msg);
}
}
异常的使用原则
1)在当前方法声明中使用try...catch语句的捕获异常。
2)一个方法中被覆盖它的方法必须抛出相同的异常或异常的子类。
3)如果父类中抛出多个异常,则覆盖方法必须抛出那些异常的一个子集,不能抛出新异常
异常处理的新特性
try…with…resourses语句
是java7中一个新的异常处理机制,它能够很容易地关闭在try...catch 语句中使用的资源。这里的资源是指在程序在完成后,必须关闭的对象,
格式:
try(Resource res = ...){
....//使用资源对象res
};
1)其中的资源必须实现了java.lang.AutoCloseable接口,该接口只有一个抽象方法:
void close() throws Exception
2)可以含有catch 和 finally 子句。catch和finally子句将会在try...catch...resources子句中打开的资源被关闭之后得到调用
public static void method02() throws IOException {
System.out.println("这里是使用try...with...resources的例子\n");
try (Scanner sc = new Scanner(Paths.get("F:/file/005.txt"))){
while (sc.hasNext()){
System.out.println(sc.next());
}
}
}
捕获多个异常
java7中,可以在同一个catch子句中捕获多个异常类型,在多个异常类之间用 “ | ” 隔开
public static void main(String[] args) {
try {
// method01();
method02();
}catch (NullPointerException | IOException e){
System.out.println("再次捕获一个:" + e);
}
}
说明:
捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不能对异常变量重新赋值。捕获多个异常
不仅可以减少代码冗余,使代码更简洁,还可以提高效率。
简单处理反射方法的异常类
java7 中引入一个新的父类ReflectiveOperationException,用于通过一个异常来捕获其他所有子异常,为
相关异常提供一个公共父类。
格式:
catch(ReflectiveOperetionException e){...}
public static void method03()throws Exception{
try {
Class c = Class.forName("chapter6.User"); //获取User类的对象
Method method = c.getMethod("method03"); //获得method03()方法
method.invoke(c.newInstance()); //调用method03()
}catch (ReflectiveOperationException ex){
System.out.println("程序发生了异常");
ex.printStackTrace();
}
}