Java中的异常处理

时间:2019-02-11
本文章向大家介绍Java中的异常处理,主要包括Java中的异常处理使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

简介

我们在编写代码的时候,有时候IDE会给出以下提示:

未处理的异常:java.lang.FileNotFoundException. 

点击提示后,一般有这两个选项:

1.在方法签名添加exception.

2.使用try/catch包围 .

使用方法1处理后:

public class BasicException {
    public static void main(String[] args) throws FileNotFoundException {
        ObjectInputStream ois = new ObjectInputStream
                (new FileInputStream(new File("f:\\")));
    }
}

 其实还需要处理IOException.

方法2:

    public static void main(String[] args) {
        try {
            ObjectInputStream ois = new ObjectInputStream
                    (new FileInputStream(new File("f:\\")));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

直接处理IOException. 

以上就是两种异常处理的方式.

还有Error,系统不会提示你处理Error:

    public static void main(String[] args) {
        int[] arr = new int[Integer.MAX_VALUE];
        System.out.println(arr[arr.length - 1]);
    }

运行后:

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
    at exception.BasicException.main(BasicException.java:5)

"main"线程中出现了java.lang.OutOfMemoryError: 所请求的数组大小超过了虚拟机限制.

异常处理可以让程序变得更加健壮,

Throwable,Error与Exception

上面的FileNotFoundException有一个父类叫IOException,而IOException的父类是Exception.OutOfMemoryError的父类是VirtualMachineError,VirtualMachineError的父类就是Error,而Exception与Error共同的父类叫做Throwable.

Java拥有相当完善的异常处理系统.Throwable作为顶级父类,下面有Exception与Error两个子类,两个子类又有若干子类.这里主要说说Exception.

Error主要是导致系统崩溃的问题,比如内存溢出错误,会直接导致程序停止运行,而且我们不能捕获它们.而Exception往往就是代码的问题,我们可以对其进行处理,比如捕获或者抛出.

异常分为检查型异常非检查型异常,非检查型异常又叫做运行时异常,有一个单独的类:RuntimeException,这时所有运行时异常的父类.

上面所提到的FileNotFoundException就是一种检查型异常,需要在代码中进行捕获(try/catch)或抛出(throws).而RuntimeException我们不需要在代码中进行处理.运行时异常只有在运行时才出现,比如广大程序员的噩梦:NullPointerException(空指针异常).

使用IntelliJ IDEA寻找Exception的子类,一共找到893个(JDK 1.8),Error共有51个子类,可以说已经把绝大多数的情况包含进去了,但是有的时候我们需要捕获的异常不在这些里面,我们也可以自定义异常,只需继承Exception类就可以.

throw与throws

两个都有抛出的意思,但是应用场景不同.

throws一般在方法定义中,用来通知调用者需要进行处理,比如:

    public static void main(String[] args) throws IOException {}

throws也是有讲究的,:你调用的方法throws了什么异常你就需要throws什么异常.而在子类重写父类方法的关系下,情况还更复杂,下面把各种情况都介绍一下:

1.与父类抛出相同的异常:

class Task {
    void method () throws FileNotFoundException, InterruptedException {}
}

class Test extends Task{
    @Override
    void method() throws FileNotFoundException, InterruptedException {}
}

2.抛出部分异常 :

class Task {
    void method () throws FileNotFoundException, InterruptedException {}
}

class Test extends Task{
    @Override
    void method() throws InterruptedException {}
}

3.也可以抛出父类异常的子类:

class Task {
    void method () throws IOException {}
}

class Test extends Task{
    @Override
    void method() throws FileNotFoundException {}
}

4.不可以是父类异常的父类,不能比父类多

class Task {
    void method1 () throws  RuntimeException {}
    void method2() throws FileNotFoundException {}
}

class Test extends Task{
    @Override
    void method1() throws  Exception {}  //不能是父类异常的父类
    @Override
    void method2() throws FileNotFoundException, EOFException{}  //不能比父类异常多
}

 而throw则用于方法体中,将异常抛出给调用者:

    public static void main(String[] args) throws IOException {
        exception();
    }
    
    private static void exception() throws IOException {
        throw new IOException();
    }

也可以创建一个异常对象,直接抛出:

    private static void exception() throws IOException {
        IOException e = new IOException();
        throw e;
    }

需要注意的一点是,如果throw的是非检查型异常,则不需要给调用者处理,检查型异常则必须抛出给调用者处理(上面的情况):

    public static void main(String[] args) {
        exception();
    }

    private static void exception() {
        throw new RuntimeException(); //非检查型异常,不需要抛给调用者.
    }

try/catch/finally

在try中处理可能发生检查型异常的代码(如IOException),在catch中进行捕获,并编写处理异常的代码,finally无论是否发生异常都会执行得到,一般用来释放资源,比如关闭流:

 public static void main(String[] args){
        DataInputStream dis = null;
        try {
             dis = new DataInputStream(new FileInputStream(new File("F:\\")));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

printStackTrace()与 getStackTrace()是两种常见的处理方式,printStackTrace()是通过System.err输出错误调用栈:

public class BasicException {
    public static void main(String[] args) {
        C c = new C();
        try {
            c.catchB();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class A{
     void exception() throws IOException {
         throw new IOException();
     }
}

class B extends A{
    void catchA() throws IOException {
        exception();
    }
}

class C extends B{
    void catchB() throws IOException {
        catchA();
    }
}

运行结果:

java.io.IOException
	at exception.A.exception(BasicException.java:18)
	at exception.B.catchA(BasicException.java:24)
	at exception.C.catchB(BasicException.java:30)
	at exception.BasicException.main(BasicException.java:9)

 getStackTrace()是获取信息,但是不输出,将上面catch中的方法替换为e.getStackTrace()之后,不会输出任何信息.

catch块可以有多个,异常的细分程度从上到下依次降低,这里只是举一个例子,只要有其中一个异常被捕获,就结束执行try块.

        catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

 try块是必选的,其余两个块至少应该有一种.即拥有如下三种形式:

1.
 try {

 } catch(Exception e) {

 } finally {

 }

2.
 try {

 } catch(Exception e) {

 } 

3. try {

 } finally {

 } 

自定义异常

如果想要编写我们自定义的异常,只需继承Exception类即可:

public class BasicException {
    public static void main(String[] args) throws MyException {
        throw new MyException();
    }
}

class MyException extends Exception{}

Exception类中有多个构造器,主要是定义抛出异常时显示的消息,在抛出异常对象或捕获的时候,可以利用super(消息)来自定义抛出异常时显示的信息:

public class BasicException {
    public static void main(String[] args) throws MyException {
        new ThrowException().throwException();
    }
}

class MyException extends Exception{
    MyException(int number){
        super("自定义异常:" + number);
    }
}

class ThrowException{
    void throwException() throws MyException {
        throw new MyException(1);
    }
}

运行结果

Exception in thread "main" exception.MyException: 自定义异常:1
......