Java学习系列文章第五篇:说说Java中的异常

在正常的程序设计中,程序异常处理是非常关键和重要的一部分。试想一个项目中没有一个好的异常处理,这个项目会怎么样?

什么是异常

异常其实是程序上的错误,包括程序逻辑错误和系统错误。比如数组下标越界、内存溢出等,这些都是意外的情况,错误在我们的程序的编写过程中会经常发生,包括编译期间和运行期间的错误。在编译期间出现的错误编译器会帮助我们修正,可是在运行期间的错误编译器就无能为力了,并且运行期间的错误往往是难以预料的。

程序出现了错误,我们不能不去处理,这样的程序的健壮性太差了。为了提高程序的健壮性我们要合理的解决这些错误!于是Java中提供了异常的处理机制,通过异常来处理程序运行期间中出现的错误。通过这一特性,我们可以很好的提高程序的健壮性。

Java是一个全面的面向对象语言,不像PHP那样,既支持过程式编程,也支持面向对象编程。Java中异常的父类是java.lang.Throwable类。在Java中定义很多的的异常类,比如OutOfMenoryError、NullPointerException、IndexOutOfBoundsException等。

Exception 类的层次

所有的异常类是从 java.lang.Exception 类继承的子类。

  • Exception 类是 Throwable类的子类。除了Exception类外,Throwable还有一个子类Error 。
    Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
  • Error 用来指示运行时环境发生的错误。
    例如,JVM 内存溢出。一般地,程序不会从错误中恢复。

异常类有两个主要的子类:IOException 类和 RuntimeException 类。

Exception,也就是我们经常见到的一些异常情况,例如NullPointerException、IndexOutOfBoundsException等,这些异常时是我们可以处理的异常。

Exception类的异常包括checked exception和unchecked exception(unchecked exception也称作运行时异常RuntimeException,Exception类的异常都是在运行期间发生的),对于运行时异常,Java编译器不要求必须进行异常处理捕获处理或者抛出,这个由程序员自行决定。

checked exception(检查异常),也称为非运行时异常(运行时异常以外的异常就是非运行时异常),Java编译器强制程序员必须捕获处理,比如常见的IOException和SQLException。对于非运行时异常如果不进行捕获或者抛出处理,Java编译器都不会通过。

在网上找了一个图,能够很清楚的描述在Java中,异常类的结构层次(有些时候语言就略显苍白,不如图片或者视频表现力丰富)。

image
在Java中,所有的异常都是继承至java.lang.Throwable类。Error类是error类型异常的父类,Exception类是exception类型异常的父类,RuntimeException类是所有运行时异常的父类,RuntimeException以外的并且继承Exception的类是非运行时异常。

  • 典型的RuntimeException包括NullPointerException、IndexOutOfBoundsException、IllegalArgumentException等。
  • 典型的非RuntimeException包括IOException、SQLException等。

Java如何处理异常

在Java中如果需要处理异常,必须先对异常进行捕获(这一点是和PHP是相同的)。使用try和catch关键字进行处理。具体的规则如下:

try{
  // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}finally{
  // 程序代码
}

来段实际的代码:

import java.io.*;
public class ExcepTest{
 
   public static void main(String args[]){
    try {
     File file = new File("/Users/sam/a.txt");
     if(!file.exists())
       file.createNewFile();
    } catch (IOException e) {
       e.printStackTrace();
    }
   }
}

被try块包围的代码说明这段代码可能会发生异常,一旦发生异常,异常便会被catch捕获到,然后需要在catch块中进行异常处理。这是一种处理异常的方式。在Java中还提供了另一种异常处理方式即抛出异常,顾名思义,也就是说一旦发生异常,我把这个异常抛出去,让调用者去进行处理,自己不进行具体的处理,此时需要用到throw和throws关键字。

我们看下面的代码:

public class Main {
   public static void main(String[] args) {
       try {
           createFile();
       } catch (Exception e) {
           // TODO: handle exception
       }
   }
    
   public static void createFile() throws IOException{
       File file = new File("/Users/sam/a.txt);
       if(!file.exists())
           file.createNewFile();
   }
}

这段代码和上面一段代码的区别是,在实际的createFile方法中并没有捕获异常,而是用throws关键字声明抛出异常,即告知调用者此方法可能会抛出IOException,需要调用者进行捕获处理。那么在main方法中调用createFile方法的时候,采用try...catch块进行了异常捕获处理。

还可以使用throw关键字进行抛出异常。看下面的例子:

package exception;

/**
 * Created by Sam on 18/6/17.
 */
public class Main {

    public static void main(String[] args){
        People people = new People("Sam",new Byte("25"));
        people.sayAge();
    }
}


 class People {

    private String name;
    private Byte age;

    public People(String name, Byte age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Byte getAge() {
        return age;
    }

    public void setAge(Byte age) {
        this.age = age;
    }

    public Byte sayAge(){
        if (age > Byte.MIN_VALUE){
            throw new MyException("年龄太大了","100" );
        }
        return age;
    }
}


public class MyException extends RuntimeException {

    private String code;

    public MyException(String message, String code) {
        super(message);
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

上面就是利用throw关键字进行手动抛出异常。调用者可以捕获处理异常,也可以不用处理异常。下面我们就修改一下代码进行捕获处理:

public class Main {

    public static void main(String[] args){
        People people = new People("Sam",new Byte("25"));
        try {
            people.sayAge();
        }catch (Exception e){
            System.out.println(e);
        }

    }
}
程序输出:
exception.MyException: 年龄太大了

也就说在Java中进行异常处理的话,对于可能会发生异常的代码,可以选择三种方法来进行异常处理:

1、对代码块用try..catch进行异常捕获处理;

2、在该代码的方法体外用throws进行抛出声明,告知此方法的调用者这段代码可能会出现这些异常,你需要谨慎处理。此时有两种情况:

如果声明抛出的异常是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。

如果声明抛出的异常是运行时异常,此方法的调用者可以选择地进行异常捕获处理。

3、在代码块用throw手动抛出一个异常对象,此时也有两种情况,跟2)中的类似:

如果抛出的异常对象是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。

如果抛出的异常对象是运行时异常,此方法的调用者可以选择地进行异常捕获处理。(如果最终将异常抛给main方法,则相当于交给jvm自动处理,此时jvm会简单地打印异常信息)

关于Java的异常机制就暂时说到这里。

相关文章

此处评论已关闭