Java核心技术 异常

异常概念

程序执行中发生不正常的情况称之为异常,可以将其理解为程序的漏洞,会导致程序崩溃。

异常体系结构

在Java体系中异常用Throwable类表示,其下面又分出两类:Error和Exception。

  1. Error指JVM无法解决的问题,如JVM内部崩溃或操作系统出错,这类错误一般不编写特定代码进行处理。

  2. Exception指除JVM不可解决的问题外,其他因编程错误或偶然发生的一般性问题引起的不正常情况,这类错误要通过编写针对性代码进行处理。其可以分为两大类:运行期异常和编译器异常(处理异常的理想时期)

    (1) RuntimeException类及其子类异常(运行期异常)

    运行期异常是不检查异常(JVM不会在编译期检查错误),这些异常一般是由程序逻辑错误引起的,可以选择捕获处理,不处理也可以运行程序。

    (2) 除RuntimeException异常外的Exception子类(编译期异常)

    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过,一般情况下不自定义检查异常。

在这里插入图片描述

异常处理

try-catch-finally

try块中的程序如果发生异常会转到catch块进行异常匹配,若有多个catch块则会顺序匹配,因此多重catch块的异常类型会从小到大写,无论代码是否出现异常最终都会执行finally块中的代码,因此finally块中一般放释放资源等收尾善后性质的语句。

try
{
   // 可能发生异常的程序代码
}catch(ExceptionName e1)
{
   //Catch捕获异常处理
}catch(ExceptionName e2){

   //Catch捕获异常处理
}finally{
  // 无论是否有异常都执行的程序代码
}

Throwable 类主要方法

方法名 作用
getMessage() 返回关于发生的异常的详细信息
getCause() 返回一个Throwable 对象代表异常原因
toString() 使用getMessage()的结果返回类的串级名字
printStackTrace() 打印toString()结果和栈层次到System.err,即错误输出流
getStackTrace() 返回一个包含堆栈层次的数组
fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中

throw/throws

如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明,throws 关键字放在方法签名的尾部,可以抛出多个异常,异常之间用逗号隔开。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。

public class Test
{
  //throws用于声明,即告诉JVM我这个代码可能会抛出异常,不一定有异常
  public void exceptionDemo(int a) throws Exception
  {
    //throw是抛出异常,一定有异常,当使用throw抛出异常时,其所在方法必须用throws声明会抛异常,反之则不必须
    throw new RemoteException();
  }
}

注意事项

  1. catch 不能独立于 try 存在
  2. 在 try/catch 后面添加 finally 块并非强制性要求
  3. try 代码后不能既没 catch 块也没 finally 块
  4. 当使用try/catch嵌套时有可能发生异常丢失

注意事项4的实例

class VeryImportantException extends Exception{
    public VeryImportantException(){
        super("Hello");
    }
    @Override
    public String toString() {
        return "A very important Exception";
    }
}
class HoHumException extends Exception{
    public HoHumException(){
        super("Hi");
    }
    @Override
    public String toString() {
        return "A trivial exception";
    }
}
public class LostMessage {
    public static void f() throws VeryImportantException {
        throw new VeryImportantException();
    }
    public static void h() throws HoHumException{
        throw new HoHumException();
    }

    public static void main(String[] args) {
        try{
        //外面catch只接收到了finally中的异常,即内部try的异常被finally异常覆盖
            try{
                f();
            }finally {
                h();
            }
        }catch (Exception e){
            System.out.println(e);
        }
    }
}

自定义异常

在 Java 中你可以自定义异常类,但是要遵循下列规则

  1. 所有异常都必须是 Throwable 的子类
  2. 如果希望写检查性异常类,则需要继承 Exception 类
  3. 如果希望写运行时异常类,则需要继承 RuntimeException 类

实例

自定义异常类

public class MyException extends Exception{
   //一定保证在构造方法中调用super(e)父类的构造函数,以便将异常信息插入异常栈中
    public MyException(String e){
        super(e);
    }
}

应用自定义异常类

public class Tran {
   static int avg(int n1,int n2)throws MyException{
       if (n1<0||n2<0){
           //抛出异常并传递错误信息
           throw new MyException("年龄不能小于0");
       }
       if (n1>100||n2>100){
           throw new MyException("年龄太大");
       }
       return (n1+n2)/2;
   }

    public static void main(String[] args) {
        try {
            int result=avg(2,109);
            System.out.println(result);
        }catch (MyException e){
            System.out.println(e);
        }
    }
}

常见异常

在这里插入图片描述

编译期异常

代码无法编译,必须进行异常处理才可以运行。

IOException某种I / O异常

在这里插入图片描述

ClassNotFoundException找不到类异常

在这里插入图片描述

运行期异常

代码可以正常编译,但运行时会报的异常

NullPointerException空指针异常

public class Test {
    public static void main(String[] args) {
        //指向空的数据会报NullPointerException
        int[] a = null;
        System.out.println(a[0]);
    }
}

IndexOutOfBoundsException下标越界异常

public class Test {
    public static void main(String[] args) {
        //数组下标越界,因为数组从0起到长度-1,报ArrayIndexOutOfBoundsException
        int[] a = new int[3];
        System.out.println(a[3]);
    }
}
public class Test {
    public static void main(String[] args) {
        //字符串下标越界,因为字符串底层也是由一个byte数组实现,报StringIndexOutOfBoundsException
        String s="abc";
        System.out.println(s.charAt(3));
    }
}

ClassCastException类型转换异常

public class Test {
    public static void main(String[] args) {
        //ClassCastException异常,一般多见于强转中
        Object d=new String();
        Date date=(Date)d;
    }
}

NumberFormatException转换数字格式异常

public class Test {
    public static void main(String[] args) {
        //NumberFormatException,因为字符串中存放的不是数字,所以无法直接转
        String s="abc";
        int n=Integer.parseInt(s);
    }
}

InputMismatchException输入不匹配异常

public class Test {
    public static void main(String[] args) {
        //因为输入的数据和接收变量的类型不同引发InputMismatchException异常
        Scanner scanner=new Scanner(System.in);
        int n= scanner.nextInt();
        System.out.println(n);
    }
}

ArithmeticException算数异常

public class Test {
    public static void main(String[] args) {
        //因为除数为0,不符合数学规则,触发ArithmeticException算数异常
        System.out.println(9/0);
    }
}

总结

异常对于Java程序是非常重要的,可以保证代码健壮性、安全性等,但如果没有完美解决异常的方案,请不要盲目处理,将其抛出即可,一般开发中还是尽量避免不必要的异常。

Author
小葳宝贝最爱吃饭
posted @ 2021-07-08 21:50  小葳宝贝最爱吃饭  阅读(69)  评论(0)    收藏  举报