JavaSE学习笔记(6)---异常

JavaSE学习笔记(6)---异常

​ 软件程序在运行过程当中,很是可能遇到问题,咱们称之为异常,英文是:Exception,意思是例外。遇到这些例外状况,或者叫异常,咱们怎么让写的程序作出合理的处理,安全的退出,而不至于程序崩溃呢?java

1.异常产生的缘由及使用原则

在 Java 中一个异常的产生,主要有以下三种缘由:数据库

  1. Java 内部错误发生异常,Java 虚拟机产生的异常。
  2. 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,通常须要在某些类中集中处理这些异常。
  3. 经过 throw 语句手动生成的异常,这种异常称为检査的异常,通常用来告知该方法的调用者一些必要的信息。

Java 经过面向对象的方法来处理异常。在一个方法的运行过程当中,若是发生了异常,则这个方法会产生表明该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。数组

咱们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到可以处理该类型异常的对象,这一个过程称为捕获(catch)异常安全

Java 异常强制用户考虑程序的强健性和安全性。异常处理不该用来控制程序的正常流程,其主要做用是捕获程序在运行时发生的异常并进行相应处理。编写代码处理某个方法可能出现的异常,可遵循以下三个原则:学习

  1. 在当前方法声明中使用 try catch 语句捕获异常。
  2. 一个方法被覆盖时,覆盖它的方法必须拋出相同的异常或异常的子类。
  3. 若是父类抛出多个异常,则覆盖方法必须拋出那些异常的一个子集,而不能拋出新异常。

2.异常的类型

在 Java 中全部异常类型都是内置类 java.lang.Throwable 类的子类,即 Throwable 位于异常类层次结构的顶层。Throwable 类下有两个异常分支 ExceptionError,如图所示。测试

img

Throwable 类是全部异常和错误的父类,下面有 Error 和 Exception 两个子类分别表示错误和异常。其中异常类 Exception 又分为运行时异常和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。this

  • Exception 类用于用户程序可能出现的异常状况,它也是用来建立自定义异常类型类的类。
  • Error 定义了在一般环境下不但愿被程序捕获的异常。Error 类型的异经常使用于 Java 运行时由系统显示与运行时系统自己有关的错误。堆栈溢出是这种错误的一例。
  • 本章不讨论关于 Error 类型的异常处理,由于它们一般是灾难性的致命错误,不是程序能够控制的。本章接下来的内容将讨论 Exception 类型的异常处理。

运行时异常都是 RuntimeException 类及其子类异常,如 NullPointerException、IndexOutOfBoundsException 等,这些异常是不检查异常,程序中能够选择捕获处理,也能够不处理。这些异常通常由程序逻辑错误引发,程序应该从逻辑角度尽量避免这类异常的发生。线程

非运行时异常是指 RuntimeException 之外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,若是不处理,程序就不能编译经过。如 IOException、ClassNotFoundException 等以及用户自定义的 Exception 异常,通常状况下不自定义检查异常。下表中列出了一些常见的异常类型及它们的做用。指针

异常类型 说明
Exception 异常层次结构的根类
RuntimeException 运行时异常,多数 java.lang 异常的根类
ArithmeticException 算术谱误异常,如以零作除数
ArraylndexOutOfBoundException 数组大小小于或大于实际的数组大小
NullPointerException 尝试访问 null 对象成员,空指针异常
ClassNotFoundException 不能加载所需的类
NumberF ormatException 数字转化格式异常,好比字符串到 float 型数字的转换无效
IOException I/O 异常的根类
F ileN otF oundException 找不到文件
EOFException 文件结束
InterruptedException 线程中断
IllegalArgumentException 方法接收到非法参数
ClassCastException 类型转换异常
SQLException 操做数据库异常

3.异常的处理

1.捕获异常

捕获异常是经过3个关键词来实现的:try-catch-finally。用try来执行一段程序,若是出现异常,系统抛出一个异常,能够经过它的类型来捕捉(catch)并处理它,最后一步是经过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条;finally语句最多只能有一条,根据本身的须要无关紧要)。如图所示。code

图6-10 异常处理.png

上面过程详细解析:

1. try:

try语句指定了一段代码,该段代码就是异常捕获并处理的范围。在执行过程当中,当任意一条语句产生异常时,就会跳过该条语句中后面的代码。代码中可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常作相应的处理。

一个try语句必须带有至少一个catch语句块或一个finally语句块 。

注意事项

当异常处理的代码执行结束之后,不会回到try语句去执行还没有执行的代码。

2. catch:

n-每一个try语句块能够伴随一个或多个catch语句,用于处理可能产生的不一样类型的异常对象。

n-经常使用方法,这些方法均继承自Throwable类 。

​ u-toString ()方法,显示异常的类名和产生异常的缘由

​ u-getMessage()方法,只显示产生异常的缘由,但不显示类名。

​ u-printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。

n-catch捕获异常时的捕获顺序:

​ u-若是异常类之间有继承关系,在顺序安排上需注意。越是顶层的类,越放在下面,再否则就直接把多余的catch省略掉。 也就是先捕获子类异常再捕获父类异常。

2. finally:

n-有些语句,不论是否发生了异常,都必需要执行,那么就能够把这样的语句放到finally语句块中。

n-一般在finally中关闭程序块已打开的资源,好比:关闭文件流、释放数据库链接等。

try-catch-finally语句块的执行过程:

try-catch-finally程序块的执行流程以及执行结果比较复杂。

基本执行过程以下:

程序首先执行可能发生异常的try语句块。若是try语句没有出现异常则执行完后跳至finally语句块执行;若是try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块能够有多个,分别捕获不一样类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,若是有的话,则不论是否发生异常,finally语句都会被执行。

注意事项

  1. 即便try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再经过return退出
  2. finally语句块只有一种状况是不会执行的,那就是在执行finally以前遇到了System.exit(0)结束程序运行

典型代码

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test8 {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("d:/a.txt");
            char c = (char) reader.read();
            char c2 = (char) reader.read();
            System.out.println("" + c + c2);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

2.抛出异常

当CheckedException产生时,不必定马上处理它,能够再把异常throws出去。

在方法中使用try-catch-finally是由这个方法来处理异常。可是在一些状况下,当前方法并不须要处理发生的异常,而是向上传递给调用它的方法处理。

若是一个方法中可能产生某种异常,可是并不能肯定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。

若是一个方法抛出多个已检查异常,就必须在方法的首部列出全部的异常,之间以逗号隔开。

注意事项

方法重写中声明异常原则:子类重写父类方法时,若是父类方法有声明异常,那么子类声明的异常范围不能超过父类声明的范围。

典型代码

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
 
public class Test9 {
    public static void main(String[] args) {
        try {
            readFile("joke.txt");
        } catch (FileNotFoundException e) {
            System.out.println("所需文件不存在!");
        } catch (IOException e) {
            System.out.println("文件读写错误!");
        }
    }  
    public static void readFile(String fileName) throws FileNotFoundException,          
    IOException {
        FileReader in = new FileReader(fileName);
        int tem = 0;
        try {
            tem = in.read();
            while (tem != -1) {
                System.out.print((char) tem);
                tem = in.read();
            }
        } finally {
            in.close();
        }
    }
}

4.自定义异常

  1. 在程序中,可能会遇到JDK提供的任何标准异常类都没法充分描述清楚咱们想要表达的问题,这种状况下能够建立本身的异常类,即自定义异常类。

  2. 自定义异常类只需从Exception类或者它的子类派生一个子类便可。

  3. 自定义异常类若是继承Exception类,则为受检查异常,必须对其进行处理;若是不想处理,可让自定义异常类继承运行时异常RuntimeException类。

  4. 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另外一个是带有详细信息的构造器。

示例

自定义异常:

/**IllegalAgeException:非法年龄异常,继承Exception类*/
class IllegalAgeException extends Exception {
    //默认构造器
    public IllegalAgeException() {
     
    }
    //带有详细信息的构造器,信息存储在message中
    public IllegalAgeException(String message) {
        super(message);
    }
}

自定义异常的使用:

class Person {
    private String name;
    private int age;
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setAge(int age) throws IllegalAgeException {
        if (age < 0) {
            throw new IllegalAgeException("人的年龄不该该为负数");
        }
        this.age = age;
    }
 
    public String toString() {
        return "name is " + name + " and age is " + age;
    }
}
 
public class TestMyException {
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setName("Lincoln");
            p.setAge(-1);
        } catch (IllegalAgeException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        System.out.println(p);
    }
}

执行结果:

图6-11 示例6-11运行效果图.png

5.使用异常机制的建议

1.要避免使用异常处理代替错误处理,这样会下降程序的清晰性,而且效率低下。

2.处理异常不能够代替简单测试---只在异常状况下使用异常机制。

3.不要进行小粒度的异常处理---应该将整个任务包装在一个try语句块中。

4.异常每每在高层处理(先了解!后面作项目会说!) 。

相关文章
相关标签/搜索