Java:异常

异常

  程序中,代码出现错误,程序就会终止运行。
  异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。
  异常处理是衡量一门语言是否成熟的标准之一,主流的语言 Java、C++、C# 等支持异常处理机制,异常处理机制可以让程序有更好的容错性,使程序代码更健壮(遗憾的是传统的 C 语言却没有异常处理,只能程序通过使用方法的特定返回值来表示异常情况,并且使用 if 语句来判断正常和非正常情况)。

没有一场极致存在的缺点

1:使用方法的返回值来表示异常情况有限,无法穷举所有的异常情况
2:异常流程代码和正常流程代码混合一起,增大了程序的复杂性,可读性差
3:随着系统规模的不断扩大,程序的可维护性极低

针对与上组没有异常机制的缺点,解决方案为:

1:把不同类型的异常情况描述成不同类(称之为异常类)
2:分离异常流程代码和正确流程代码
3:灵活处理异常,如果当前方法处理不了,应该交给调用者来处理

注:Throwable 类是 Java 语言中所有错误或异常的超类。

非正常情况(出现后程序会终端)

Error:表示错误,一般指 JVM 相关的不可修复的错误。如:系统崩溃,内存溢出,JVM 错误等,由 JVM 抛出,我们不需要处理。  
几乎所有的子类都是以 Error 作为类名的后缀(但是测试框架的设计者,却把大量的异常类设为 Error)。  
Exception:表示异常,指程序中出现不正常的情况,该问题可以修复。几乎所有的子类都是以 Exception 作为类名的后缀。  
出现异常可以把异常的简单类名,拷贝到API中查。

1:常见的 Error

StackOverflowError:当应用程序递归太深而发生内存溢出时,抛出该错误。

2:常见的 Exception

1.NullPointerException:空指针异常,一般指当对象为 null 的时候,调用了该对象的方法,字段
2.ArrayIndexOutOfBoundsException:数组的索引越界(小于 0 或者大于等于数组长度)
3.NumberFormatException:数字格式化异常,一般指,把非 0~9 的字符串转换为整数

如果异常出现,会立刻终止程序,所以需要处理异常
1该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)
2在方法中使用try-catch的语句块来处理异常

使用try-catch捕获单个异常,语法如下

try{
    编写可能会出现异常的代码
}catch(异常类型 e){
    处理异常的代码
    //记录日志/打印异常信息/继续抛出异常等
}

注意:try 和 catch 都不能单独使用,必须连用(try 也可以只和 finally 连用)

获取异常信息 Throwable 类的方法

1String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)
2String toString():获取异常的跟踪栈信息(不使用)
3void printStackTrace():打印异常的跟踪栈信息并输出到控制台,不需要使用 System.out.println();   该方法包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用 printStackTrace

注:目前(开发时)在 catch 语句块中,必须写:e.printStackTrace()
目的:查看异常的具体信息,方便调试和修改

使用try-catch捕获多个异常

try{
    编写可能会出现异常的代码
}catch(异常类型A e){
    //当 try 出现 A 类型的异常,就用该 catch 来捕获处理异常的代码
    //记录日志/打印异常信息/继续抛出异常等
}catch(异常类型B e){
    //当 try 出现 B 类型的异常,就用该 catch 来捕获处理异常的代码
    //记录日志/打印异常信息/继续抛出异常等   
}

注:

1.一个 catch 语句,只能捕获一种类型的异常,如果需要捕获多种异常,就得使用多个 catch 语句(JDK1.7 后有强化的catch)。
2.代码在一瞬间只能出现一种类型的异常,只需要一个 catch 捕获,不可能同时出现多个异常。

finally

finally语句块:表示最终都会执行的代码,无论有没有异常。

  当在 try 语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等)。都得在使用完成之后,最终关闭打开的资源。

finally 的两种语法

1try...finally:此时没有catch来捕获异常,因为此时根据应用场景会自动抛出异常,不需要自己处理。
2try...catch...finally:自身需要处理异常,最终还得关闭资源
注:finally 不能单独使用
当只有在try或者catch中调出退出 JVM 的相关方法,此时 finally 才不会执行,否则 finally 永远会执行

System.exit():退出JVM

异常(Exception)的分类:

1、编译时期异常:checked 异常,在编译时期就会检查,如果没有处理异常则编译失败。  
2、运行期异常:runtime 异常,在运行时期,检查异常,在编译时期,编译器不会检测运行异常(不报错)。  
运行异常:在编译时期,可处理也可以不处理

抛出异常

throw:运用与方法内部,用于给调用者返回一个异常对象,和 return 一样会结束当前方法。
throws:运用与方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。

throw语句:运用于方法内部,抛出一个具体的异常现象

throw new 异常类("异常信息");//终止方法

throw:

一般的,当一个方法出现不正常的情况的时候,不知道该方法应该返回什么,此时就一直返回一个错误,在 catch 语句块中继续向上抛出异常。
return 是返回一个值,throw 是返回一个错误,返回给该方法的调用者。

  如果每一个方法都放弃处理异常都直接通过 throws 声明抛出,最后异常会跑到main方法,如果此时 main 方法不处理,继续抛出给 JVM 底层的处理机制就是打印异常的跟踪栈信息。
runtime 异常,默认就是这种处理方式。

自定义异常类:

  Java 中有不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是 SUN 没有定义好的,此时需要根据自己业务的异常情况来定义异常类。

异常类如何定义:

方式1:自定义一个受检查的异常类:自定义类,并继承于 java.lang.Exception
方式2:自定义一个运行时期的异常类:自定义类,并继承于 java.lang.RuntimeException
异常转译:

  当位于最上层的子系统不需要关心底层的一场戏节时,常见的做法就是捕获原始的异常,把它转换为一个新的不同类型的异常,再抛出新的异常。

异常链:

  把原始的异常包装为新的异常类,从而形成多个异常的有序排列,有助于查找生成异常类的根本原因。

Java7 的异常新特性(Android 用不到 Java7,支持 Java5/Java6 的语法)

1:增强的 throw
2:多异常捕获
3:自动资源关闭

Java7 中处理抛出异常更加精确了,不再笼统地使用 Exception 声明抛出

处理异常的原则:

1:异常只能用于非正常情况,try-catch 的存在也会影响性能
2:需要为异常提供说明文档,比如 java.doc,如果自定义了异常或某一个方法抛出了异常,应该记录在文档注释中
3:尽可能避免异常
4:异常的粒度很重要,应该为一个基本操作定义一个 try-catch 块,不要为了简便,将几百行代码放到一个 try-cathc 块中
5:不建议在循环中进行异常处理,应该在循环外对异常进行捕获处理(在循环之外使用 try-catch6:自定义异常尽量使用 RuntimeException 类型

捕获异常的语句块运行顺序:

public class ExceptionTest {
    public static void main(String[] args) {
        System.out.println(testMethod());
    }

    static int testMethod() {
        int t = 1;
        try {
            System.out.println("进入try语句块----t:" + t);
            t++;
            System.out.println(t / 0);
            System.out.println("离开try语句块----t:" + t);
            return t;
        } catch (ArithmeticException e) {
            System.out.println("进入ArithmeticException异常----t:" + t);
            t++;
            System.out.println("结束ArithmeticException异常----t:" + t);
            return t;
        } catch (Exception e) {
            System.out.println("进入Exception异常----t:" + t);
            t++;
            System.out.println("离开Exception异常----t:" + t);
            return t;
        } finally {
            System.out.println("进入finally语句块----t:" + t);
            t = 10;
            System.out.println("离开finally语句块----t:" + t);
            return t;
        }
    }
}

输出结果为:

进入try语句块----t:1
进入ArithmeticException异常----t:2
结束ArithmeticException异常----t:3
进入finally语句块----t:3
离开finally语句块----t:10
10

猜你喜欢

转载自blog.csdn.net/qq_33811662/article/details/80631563