一、异常

1、什么是异常

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

2、java异常类

         在Java中提供了大量的异常类,查阅API文档,Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Javathrow 语句抛出。类似地,只有此类或其子类之一才可以是 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,我们以此为例。

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

  1. public class TestException {
  2. public static void main(String[] args) {
  3. int x = 5;
  4. int y = 0;// 除数为0
  5. System.out.println(x / y);
  6. }
  7. }

运行结果为:

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

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


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

  1. public class TestException {
  2. public static void main(String[] args) {
  3. int x = 5;
  4. int y = 0;// 除数为0
  5. try {//监控区域
  6. if (y == 0) {
  7. throw new ArithmeticException();
  8. //通过throw语句抛出异常
  9. }
  10. System.out.println(x / y);
  11. } catch (ArithmeticException e) {//捕捉异常
  12. System.out.println("程序出现异常,除数不能为0");
  13. }
  14. }
  15. }

运行结果为:

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


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


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

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

运行结果为:

程序出现异常,除数不能为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。

代码示例:

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

运行结果为:

捕获的异常信息为/ 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关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者。

代码示例:

  1. public class TestException {
  2. public static void main(String[] args) {
  3. try {
  4. int result = divide(4, 0);
  5. System.out.println(result);
  6. } catch (ArithmeticException e) {
  7. System.out.println("捕获的异常信息为" + e.getMessage());
  8. } finally {
  9. System.out.println("进入finally代码块");
  10. }
  11. System.out.println("程序继续向下执行");
  12. }
  13. public static int divide(int x, int y) throws ArithmeticException// 抛出异常
  14. {
  15. int result = x / y;
  16. return result;
  17. }
  18. }

throws抛出异常规则:

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

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


5、使用throw抛出异常

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

代码示例:

  1. public class MyException extends Exception {// 创建自定义异常类
  2. private String message;// 定义String类型变量
  3. private int value;// 定义int类型变量
  4. public MyException() {
  5. super();
  6. }
  7. public MyException(String message, int value) {
  8. this.message = message;
  9. this.value = value;
  10. }
  11. public int getValue() {
  12. return value;
  13. }
  14. public String getMessage() {
  15. return message;
  16. }
  17. }

测试:

  1. public class TestMyException {
  2. public static void main(String[] args) {
  3. try {// 包含可能发生异常的语句
  4. int result = divide(4, -1);// 调用divide()方法
  5. System.out.println(result);
  6. } catch (MyException e) {// 处理自定义异常
  7. System.out.println(e.getMessage());// 输出异常信息
  8. System.out.println("错误的负数是:" + e.getValue());// 输出异常值
  9. } catch (ArithmeticException e) { // 处理ArithmeticException异常
  10. System.out.println("除数不能为0"); // 输出提示信息
  11. } catch (Exception e) { // 处理其他异常
  12. System.out.println("程序发生了其他的异常"); // 输出提示信息
  13. }
  14. System.out.println("over");
  15. }
  16. public static int divide(int x, int y) throws MyException// 定义方法抛出
  17. {
  18. if (y < 0) {// 判断参数是否小于0
  19. throw new MyException("出现了除数是负数的情况!------/by FuShu", y);// 异常信息
  20. }
  21. return x / y;// 返回值
  22. }
  23. }

运行结果为:

出现了除数是负数的情况!------/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编程基础-异常的更多相关文章

  1. Java开发知识之Java编程基础

    Java开发知识之Java编程基础 一丶Java的基础语法 每个语言都有自己的语法规范.例如C++ 入口点是main. 我们按照特定格式编写即可. Java也不例外. Java程序的语法规范就是 Ja ...

  2. Java编程基础-面向对象(中)

    本章承接Java编程基础-面向对象(上)一文. 一.static关键字 在java中,定义了一个static关键字,它用于修饰类的成员,如成员变量.成员方法以及代码块等,被static修饰的成员具备一 ...

  3. Java编程基础——数组和二维数组

    Java编程基础——数组和二维数组 摘要:本文主要对数组和二维数组进行简要介绍. 数组 定义 数组可以理解成保存一组数的容器,而变量可以理解为保存一个数的容器. 数组是一种引用类型,用于保存一组相同类 ...

  4. Java编程基础——标识符和关键字

    Java编程基础——标识符和关键字 摘要:本文主要介绍标识符和关键字. 标识符 是什么 Java语言中,为各种变量.方法.类和包等起的名字,统统称之为Java标识符. 命名规则 ◆ 应以字母.下划线. ...

  5. Java入门——(1)Java编程基础

    Java入门--(1)Java编程基础 第二章 Java编程基础   JAVA 代码的基本格式: 修饰符 class 类名{ 程序代码 }   2.1关键字:赋予了特殊含义的单词.   2.2标识符: ...

  6. java编程基础二进制

    0.java编程基础 01.二进制(原码,反码,补码) 02.位运算 03.移位运算符 二进制 原码,反码,补码 1.基本概念 二进制是逢2进位的进位制,0,1是基本算符. 现在的电子计算机技术全部使 ...

  7. Java编程基础——流程控制

    Java编程基础——流程控制 摘要:本文主要介绍Java编程中的流程控制语句. 分类 流程控制指的是在程序运行的过程中控制程序运行走向的方式.主要分为以下三种: 顺序结构:从上到下依次执行每条语句操作 ...

  8. Java编程基础——运算符和进制

    Java编程基础——运算符和进制 摘要:本文主要介绍运算符和进制的基本知识. 说明 分类 Java语言支持如下运算符: ◆ 算术运算符:++,--,+,-,*,/,%. ◆ 赋值运算符:=,+=,-= ...

  9. Java编程基础——常量变量和数据类型

    Java编程基础——常量变量和数据类型 摘要:本文介绍了Java编程语言的常量变量和数据类型. 常量变量 常量的定义 一块内存中的数据存储空间,里面的数据不可以更改. 变量的定义 一块内存中的数据存储 ...

随机推荐

  1. vim的tab缩进及用空格设置

    编辑~/.vimrc文件,分别设置用空格而不是用tab,一个tab多少个空格,自动缩进多少宽度,显示行号. set expandtabset tabstop=4 set shiftwidth=4 se ...

  2. app基础

    1界面:Layout 2.控件 3.整个窗口:Activity 4. ctrl + H : 查看类的继承关系 5. shift + F1:打开类的文档 6. Button button = (Butt ...

  3. Linux下使用《du》命令查看某文件及目录的大小

    du -ah --max-depth=1     这个是我想要的结果  a表示显示目录下所有的文件和文件夹(不含子目录),h表示以人类能看懂的方式,max-depth表示目录的深度. du -sh 目 ...

  4. Notice:Array to string conversion的问题

    如果后台或者前端输出这样的提示: Notice: Array to string conversion 原因是:用 echo  来输出数组,当然会报错,数组应该用print , print_r , 或 ...

  5. Sandy and Nuts

    题意: 现在有一个$n$个点的树形图被拆开,现在你知道其中$m$条边,已经$q$对点的$LCA$,试求原先的树有多少种可能. 解法: 考虑$dp$,$f(x,S)$表示$x$的子树内的点集为$S$(不 ...

  6. error:: undefined reference to symbol '__glewBufferSubData' 未定义的引用 以及 error: main.o: undefined reference to symbol 'glTexImage2D'

    在把DSO移植到QT工程中,出现了 /usr/bin/ld: KeyFrameDisplay.o: undefined reference to symbol '__glewBufferSubData ...

  7. 2、css的存在形式及优先级

    一.优先级 简单可以理解为就近原则: <html lang="en"> <head> <meta charset="UTF-8"& ...

  8. Git 移除某些文件

    一.前言 在使用 Git 版本控制中,有些文件是不需要加入到版本控制中的.如 日志( log ).编译的文件.这些随时都在变的文件,使用用一个代码库的用户.只要稍稍修改一点,或者启动一下,就会变.容易 ...

  9. Tomcat 容器的安全认证和鉴权

    大量的 Web 应用都有安全相关的需求,正因如此,Servlet 规范建议容器要有满足这些需求的机制和基础设施,所以容器要对以下安全特性予以支持: 身份验证:验证授权用户的用户名和密码 资源访问控制: ...

  10. Java判断一个数是不是快乐数

    快乐数的定义: 快乐数(happy number)有以下的特性: 在给定的进位制下,该数字所有数位(digits)的平方和,得到的新数再次求所有数位的平方和,如此重复进行,最终结果必为1. 以十进制为 ...