Java异常知识总结

1.为什么需要异常

在没有异常机制的时候我们对错误处理一般是这样实现的:通过函数的返回值来判断是否发生了异常(这个返回值通常是已经约定好了的),调用该函数的程序负责检查并且分析返回值。虽然可以解决异常问题,但是这样做存在以下缺陷:

  1. 标准不统一。返回值的约定依赖于实现者个人,可能造成标准不一致。
  2. 代码可读性与可维护性降低。将异常处理代码和程序代码混淆在一起不方便阅读,更不利于后期维护。

为了解决上述存在的问题,引入了异常机制。它在程序发生异常时,强制终止程序运行,记录异常信息并将这些信息反馈给我们,由我们来确定是否处理异常。它能使我们摆脱各种返回值的约定以及实现逻辑代码与错误处理代码的分离。

2.异常体系介绍

这里写图片描述
从图中可以看出Throwable是java所有Error和Exception的超类。

Error和Exception的区别

  • Error是程序无法处理的,如OutOfMemoryError、ThreadDeath等,出现这种情况程序将无能为力,交由JVM来处理,不过JVM在大多数情况下会选择终止线程。
  • Exception是程序正常运行中可以预料的意外情况,可能应该被捕获,进行相应处理。

CheckedException和RuntimeException的区别

  • CheckedException在源代码里必须显式地进行进行捕获处理。这是编译检查的一部分。
  • RuntimeException是运行时异常,在编译阶段不会进行检查。

3.异常语法

java 异常相关的关键字有5个:try, catch, finally, throw, throws。
语法形式

try {  
    // 可能会发生异常的程序代码  
} catch (ExceptionType1 id1) {  
    // 捕获并处理try抛出的异常类型Type1  
} catch (ExceptionType2 id2) {  
    // 捕获并处理try抛出的异常类型Type2  
} finally {  
    // 无论是否发生异常,都将执行的语句块  
}

try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。

public class Main {

    public static void main(String[] args)  {

        try {
            int i = 1 / 0;
            return;
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }

    }
}

运行结果:

finally
java.lang.ArithmeticException: / by zero
    at com.tongfang.learn.Main.main(Main.java:36)

在以下特殊情况下,finally块不会被执行:

  • 在finally语句块中发生了异常。
public class Main {

    public static void main(String[] args)  {

        try {
            int i = 1 / 0;
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
        } finally {
            throw new NullPointerException();
            System.out.println("finally"); //编译错误,语句不可达
        }

    }
}
  • 在前面的代码中用了System.exit()退出程序。
public class Main {

    public static void main(String[] args)  {

        try {
            System.exit(0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }

    }
}

运行结果:

Process finished with exit code 0

throw:对于异常可以捕获,也可以抛出,该关键字用于抛出异常,让调用者来捕获。
throws:声明一个方法可能抛出的异常。

catch匹配
异常的捕获顺序为按照程序中定义的异常顺序依次匹配,当匹配到对应的异常则进入异常处理程序。

我们看下面的程序:

public class Main {
    public static void main(String[] args)  {
        try {
            int i = 1 / 0;
        } catch (Exception e){        
            e.printStackTrace();
        } catch (ArithmeticException e) {   //编译错误
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }
    }
}

按照catch匹配原则,本例中ArithmeticException是Exception的子类,所有的Exception 将会被第一个catch捕获,后面的catch将永远不可达,所以会编译报错。因此catch 代码应按照先捕获小异常,再捕获大异常的原则实现。

异常对继承的影响
方法重写中声明异常原则:

  • 父类没有声明异常,子类则不能。
class A{
    public void method() {
    }
}

class B extends A{
    public void method() throws FileNotFoundException { 
    //编译错误,父类中该方法没有声明抛出异常。
    }
}
  • 子类不可抛出比父类更抽象的异常类,也就是子类抛出的异常类只能是父类中抛出的异常类的子类。
class A{
    public void method() throws IOException{
    }
}

class B extends A{
    public void method() throws Exception {
    //编译错误,抛出的Exception是IOException的父类
    }
}
class A{
    public void method() throws IOException{
    }
}

class B extends A{
    public void method() throws FileNotFoundException {
    //编译通过
    }
}

自定义异常:

所有异常都必须是 Throwable 的子类。
如果希望写一个检查性异常类,则需要继承 Exception 类。
如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。

例:

class MyException extends Exception {
    public MyException() {
    }

    public MyException(String message) {
        super(message);
    }
}

public class Main {
    public static void main(String[] args)  {
        try {
            throw new MyException("myException");
        } catch (MyException e){
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            System.out.println("finally");
        }

    }
}

运行结果:

myException
finally

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/cl2010abc/article/details/80705061