我是靠谱客的博主 野性毛衣,最近开发中收集的这篇文章主要介绍Java编程基础-异常,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、异常

1、什么是异常

        在java中,程序在运行时出现的不正常情况称为异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。其实就是java对不正常情况进行描述后的对象体现。


2、java异常类 

         在java中提供了大量的异常类,查阅API文档,Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。

        Throwable有两个直接的子类Error和Exception,其中,Error代表程序中产生的错误,Exception代表程序中产生的异常。

       a)    Error类称为错误类,它表示java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。对于Error一般不编写针对性的代码对其进行处理。
       b)    Exception类称为异常类,它表示程序本身可以处理的错误,在java开发程序中进行的异常处理,都是针对Exception类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其它的子类都用于表示编译时异常。对于Exception可以采用针对性的代码对其进行处理。


3、Throwable常用方法

String getMessage()   :返回此throwable的详细消息字符串

void printStackTrace()   :将此throwable及其追踪输出至标准错误流
void printStackTrace(PrintStream s)   :将此throwable及其追踪输出到指定的输出流


4、常见异常

RuntimeException子类:

a) java.lang.ArrayIndexOutOfBoundsException

    数组下标越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

b)java.lang.ArithmeticException
    算术条件异常。比如:整数除零等。

c)java.lang.NullPointerException
    空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。比如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
 d)java.lang.ClassNotFoundException
    找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
e)java.lang.NegativeArraySizeException  数组长度为负异常

 f)java.lang.IllegalArgumentException 非法参数异常

IOException

a)IOException:操作输入流和输出流时可能出现的异常。
b)FileNotFoundException   文件未找到异常

其他

a)ClassCastException    类型转换异常类
b)SQLException   操作数据库异常类
c)NoSuchFieldException   字段未找到异常
d)NoSuchMethodException   方法未找到抛出的异常
e)NumberFormatException    字符串转换为数字抛出的异常
f)StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
g)IllegalAccessException  不允许访问某类异常



二、运行时异常和编译时异常

        异常可以分为编译时被检测异常(该异常在编译时,如果没有处理(没有抛也没有try),编译失败。)和编译时不被检测的异常(运行时异常RuntimeException及其子类。在编译时,不需要处理,编译器不检查。)

 1、编译时异常(也称checked异常)

        编译时异常的特点是java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。处理方式有两种:一是使用try..catch语句对异常进行捕获;二是使用throws关键字声明抛出异常,让调用者对其处理。

2、运行时异常(也称unchecked异常)

        特点是java编译器不会对其进行检查,当程序中出现这类异常时,即时没有捕获或抛出处理,编译也能通过。运行时异常一般是由于程序中的逻辑错误引起的,在程序运行时无法恢复。



三、异常处理机制

在java应用程序中,对异常的处理要么抛出异常,要么捕获异常。

捕获异常 

1、 在Java中,异常通过try-catch语句捕获。其一般语法形式为:

       try {
            // 可能发生异常的程序代码
        } catch (ExceptionType1 e) {
            // 捕获并处置try抛出的异常类型Type1
        } catch (ExceptionType2 e) {
            // 捕获并处置try抛出的异常类型Type2
        }


         异常捕获处理过程:关键词try后的一对大括号将一块可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之外,由Java运行时系统试图寻找匹配的catch子句以捕获异常。catch语句带一个Throwable类型的参数, 表示可捕获异常类型。当try中出现异常时,catch会捕获到发生的异常,并和自己的异常类型匹配, 若匹配,则执行catch块中代码,并将catch块参数指向所抛的异常对象。catch语句可以有多个, 用来匹配多个中的一个异常,一旦匹配上后则运行其异常处理代码,try-catch语句结束。
匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。


2、示例演示:

数学上我们都知道除法中被除数不能为0,我们以此为例。

首先,演示不作任何处理时的情况。

public class TestException {
public static void main(String[] args) {
int x = 5;
int y = 0;// 除数为0
System.out.println(x / y);
}
}
运行结果为:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at test.TestException.main(TestException.java:8)

系统报了个ArithmeticException: / by zero 算术异常,并且指出是被0除


其次:我们演示捕捉throw语句抛出的除数为0的异常并处理。

public class TestException {
public static void main(String[] args) {
int x = 5;
int y = 0;// 除数为0
try {//监控区域
if (y == 0) {
throw new ArithmeticException();
//通过throw语句抛出异常
}
System.out.println(x / y);
} catch (ArithmeticException e) {//捕捉异常
System.out.println("程序出现异常,除数不能为0");
}
}
}
运行结果为:

程序出现异常,除数不能为0


        简单分析:在try监控区域通过if语句进行判断,当“除数为0”的错误条件成立时引发ArithmeticException异常,创建 ArithmeticException异常对象,并由throw语句将异常抛给Java运行时系统,由系统寻找匹配的异常处理器catch并运行相应异常处理代码,打印输出“程序出现异常,除数不能为0”,try-catch语句结束,继续程序流程。实际上,“除数为0”等ArithmeticException,是RuntimException的子类。而运行时异常将由运行时系统自动抛出,不需要使用throw语句。


最后,我们测试捕捉运行时系统自动抛出“除数为0”引发的ArithmeticException异常。

public class TestException {
public static void main(String[] args) {
int x = 5;
int y = 0;// 除数为0
try {
System.out.println(x / y);
} catch (ArithmeticException e) {//捕捉异常
System.out.println("程序出现异常,除数不能为0");
}
}
}

运行结果为:

程序出现异常,除数不能为0


        简单分析:在运行中出现“除数为0”错误,引发ArithmeticException异常。运行时系统创建异常对象并抛出监控区域,转而匹配合适的异常处理器catch,并执行相应的异常处理代码。由于检查运行时异常的代价远大于捕捉异常所带来的益处,运行时异常不可查。Java编译器允许忽略运行时异常,一个方法可以既不捕捉,也不声明抛出运行时异常。


        注意:一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会。而对于有多个catch子句的异常程序而言,应该尽量将捕获的子类异常的catch子句放在前面,同时尽量将捕获相对高层的父类异常的catch子句放在后面。否则,捕获底层的子类异常的catch子句将可能会被屏蔽。
RuntimeException异常类包括运行时各种常见的异常,RuntimeException异常类的catch子句应该放在最后面,否则可能会屏蔽其后的特定异常处理或引起编译错误。



3、try-catch语句还可以包括第三部分,就是finally子句。它表示无论是否出现异常,都应当执行的内容。

try-catch-finally语句的一般语法形式为:
       try {
            // 可能发生异常的程序代码
        } catch (ExceptionType1 e) {
            // 捕获并处置try抛出的异常类型Type1
        } catch (ExceptionType2 e) {
            // 捕获并处置try抛出的异常类型Type2
        }finally{
            //无论是否发生异常,都将执行的语句块
        }

       finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

代码示例:

public class TestException {
public static void main(String[] args) {
try {
int result = divide(4, 0);// 调用divide()方法
// int result = divide(4, 2);//测试未发生异常情况
System.out.println(result);
} catch (Exception e) {
System.out.println("捕获的异常信息为" + e.getMessage());
} finally {
System.out.println("进入finally代码块");
}
System.out.println("程序继续向下执行");
}
public static int divide(int x, int y)// 定义一个两个整数相除的方法
{
int result = x / y;// 定义一个变量result记住相除的结果
return result;// 将结果返回
}
}
运行结果为:

捕获的异常信息为/ by zero
进入finally代码块
程序继续向下执行

未发生异常测试结果为:

2
进入finally代码块
程序继续向下执行


try、catch、finally三个语句块应注意的问题: 
a)try、catch、finally三个语句块均不能单独使用,三者可以组成 try...catch...finally、try...catch、 try...finally三种结构,catch语句可以有一个或多个,finally语句最多一个。 

b)try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。 如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。 
c)多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块, 并且匹配catch语句的顺序是由上到下。

d)必须遵循语句块放置顺序try-catch-finally的顺序。

e)可嵌套 try-catch-finally 结构。比如,try中还可以有try..catch处理


抛出异常

4、throws抛出异常

       如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。例如汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割。throws语句的语法格式为:

methodName([param1,param2,..])throws ExceptionType1[,ExceptionType2..]{}
        throws关键字需要写在方法声明的后面,throws后面需要声明方法中发生异常的类型,通常将这种做法称为方法声明抛出一个异常。 使用throws关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者。

代码示例:

public class TestException {
public static void main(String[] args) {
try {
int result = divide(4, 0);
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("捕获的异常信息为" + e.getMessage());
} finally {
System.out.println("进入finally代码块");
}
System.out.println("程序继续向下执行");
}
public static int divide(int x, int y) throws ArithmeticException// 抛出异常
{
int result = x / y;
return result;
}
}

throws抛出异常规则:

a) 如果是运行时异常,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
b)如果是编译时异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误

c)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出。


5、使用throw抛出异常

        throw总是出现在函数体内,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。 由于异常是异常类的实例对象,我们可以创建异常类的实例对象通过throw语句抛出。该语句的语法格式为:
throw new ExceptionType();

代码示例:

public class MyException extends Exception {// 创建自定义异常类
private String message;// 定义String类型变量
private int value;// 定义int类型变量
public MyException() {
super();
}
public MyException(String message, int value) {
this.message = message;
this.value = value;
}
public int getValue() {
return value;
}
public String getMessage() {
return message;
}
}
测试:
public class TestMyException {
public static void main(String[] args) {
try {// 包含可能发生异常的语句
int result = divide(4, -1);// 调用divide()方法
System.out.println(result);
} catch (MyException e) {// 处理自定义异常
System.out.println(e.getMessage());// 输出异常信息
System.out.println("错误的负数是:" + e.getValue());// 输出异常值
} catch (ArithmeticException e) { // 处理ArithmeticException异常
System.out.println("除数不能为0"); // 输出提示信息
} catch (Exception e) { // 处理其他异常
System.out.println("程序发生了其他的异常"); // 输出提示信息
}
System.out.println("over");
}
public static int divide(int x, int y) throws MyException// 定义方法抛出
{
if (y < 0) {// 判断参数是否小于0
throw new MyException("出现了除数是负数的情况!------/by FuShu", y);// 异常信息
}
return x / y;// 返回值
}
}
运行结果为:

出现了除数是负数的情况!------/by FuShu
错误的负数是:-1
over

throws和throw的区别:
a)throws使用在函数上。throw使用在函数内。
b)throws后面跟的是异常类,可以跟多个,用逗号隔开。throw后面跟的是异常对象。


四、自定义异常

        因为实际项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对于这些特有的问题可以按照java对问题的封装思想。将特有的问题,进行自定义的异常封装。在java中允许用户自定义异常,自定义异常步骤:
(1)、创建自定义异常类,且该类必须继承自Exception或其子类。(因为异常体系有一个特点,因为异常类和异常对象都被抛出。他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点。)
(2)、在方法中通过throw关键字抛出异常对象。
(3)、如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)、在出现异常方法的调用者中捕获并处理异常。

自定义异常可参见上面使用throw抛出异常的代码示例。

 异常在子父类覆盖中的体现:
(1)、子类在覆盖父类时,如果父类的抛出方法异常,那么子类的覆盖方法,只能抛出父类的异常或该异常的子类
(2)、如果父类方法中抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
(3)、如果父类或接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。

最后

以上就是野性毛衣为你收集整理的Java编程基础-异常的全部内容,希望文章能够帮你解决Java编程基础-异常所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部