钱匾 发表于 2025-10-1 13:39:26

java 异常处理

java 异常处理

1.异常体系

异常体系的顶级父类是 Throwable,这个类有两个子类:Error 和 Exception。
Throwable 听起来很像是一个接口,但是在 jdk17 中确实是一个类。


[*]Error 类及其子类:通常指程序无法处理的严重问题,如系统错误或资源不足。
[*]Exception 类及其子类:程序本身可以捕获和处理的异常,Exception 下面又可以分成两类:RuntimeException 和其他异常(编译时异常)。

[*]RuntimeException:运行时异常,编译时不需要检查,只有程序实际运行起来才能发现,一般是因为代码逻辑错误引起的。
[*]其他异常:在 Exception 类下面除了 RuntimeException 就是其他异常,也叫做编译时异常,从语法角度讲是必须进行处理的异常,如果不处理,程序不能编译通过。

2.异常捕获

1.try catch

[*]若 try 中没有出现异常,则执行完 try 中的代码后跳过 catch,继续向下执行,会输出"pass..."
[*]若 try 中出现异常,则生成一个对应的异常对象并抛出,不再执行 try 下面的代码

[*]若 catch 能够捕获 try 中抛出的异常,则程序转入 catch 代码块中执行
[*]若 catch 没有捕获 try 中抛出的异常,则程序会将异常对象向上抛出,异常被传递到该方法的调用者进行处理

[*]在这里,由于 obj = null,所以"obj.toString()"会抛出空指针异常,不会再打印下面的"try..."。然后 catch 会尝试捕获这个空指针异常,空指针异常是运行时异常,所以空指针异常是 Exception 的子类,相当于 Exception e = new NullPointerException()。catch 捕获成功,执行"throw new RuntimeException(e)",由于这里又抛出了一个异常,但是没有其他 catch 进行捕获,所以下面不会再打印"pass..."。(如果 catch 中没有抛出异常,程序在执行完 catch 的代码后可以继续向下执行)
[*]注意:try catch 可以对异常进行处理,而且可以在出现异常后继续向下执行,在开发中需要特别注意。
public class Test {
    public static void main(String[] args) {
      try {
            Object obj = null;
            System.out.println(obj.toString()); // 空指针异常

            System.out.println("try...");
      } catch (Exception e) {
            throw new RuntimeException(e);
      }
      System.out.println("pass...");
    }
}2.try catch finally
有了上面的基础,finally 就好理解多了,finally 表示必须要执行的代码:

[*]若 try 中没有出现异常,则 try --> finally --> 向下执行
[*]若 try 中出现异常,catch 尝试捕获异常

[*]若 catch 捕获成功,则 catch --> finally
[*]若 catch 捕获失败,则程序会在执行完 finally 中的代码后再停止

[*]即使在 try 或者 catch 中用 return 结束方法,finally 一样会执行。

[*]在 try 或者 catch 中 return 时,jvm 会使用一个变量保存要返回的值,即使后来在 finally 中再修改这个值,也能保证 return 的值不被修改。
[*]如果在 try 和 finally 中都有 return,此时会忽略 try,而执行 finally 的 return。

public class Test {
    public static void main(String[] args) {
      try {
            Object obj = null;
            System.out.println(obj.toString()); // 空指针异常

            System.out.println("try...");
      } catch (Exception e) {
            throw new RuntimeException(e); // catch成功并抛出另一个异常
      } finally {
            System.out.println("here is finally"); // 即使在catch中抛出一个新异常,finally一样会执行
      }
      System.out.println("pass..."); // 不会打印pass...
    }
}

/////////////////////////////////////////////////////
public class Test {
    public static void main(String[] args) {
      System.out.println(example());
    }

    public static int example() {
      int i = 0;
      try {
            i++;
            return i; // 1
      } catch (Exception e) {
            throw new RuntimeException(e);
      } finally {
            System.out.println("here is finally");
            i++; // 2
      }
    }
}

///////////////////////////////////////////////////
public class Test {
    public static void main(String[] args) {
      System.out.println(example());
    }

    public static int example() {
      int i = 0;
      try {
            i++; // 1
            i = 1 / 0; // 算术异常
            return i;
      } catch (Exception e) {
            i++; // 2
            return i;
      } finally {
            System.out.println("here is finally");
            i++; // 3
      }
    }
}

/////////////////////////////////////////////////////
public class Test {
    public static void main(String[] args) {
      System.out.println(example());
    }

    public static int example() {
      int i = 0;
      try {
            i++; // 1
            i = 1 / 0; // 算术异常
            return i;
      } catch (Exception e) {
            i++; // 2
            return i;
      } finally {
            System.out.println("here is finally");
            i++; // 3
            return i;
      }
    }
}3.try finally
try 可以直接跟 finally 搭配使用。
在这些演示中,似乎 finally 无论有没有出现异常都一定会执行,真的是这样吗?

[*]如果 try 或者 catch 退出程序,finally 不会执行
[*]finally 语句块中出现异常,会抛出异常,且不再向下执行
[*]程序所在的线程死亡,finally 不会执行
public class Test {
    public static void main(String[] args) {
      System.out.println(example());
    }

    public static int example() {
      int i = 0;
      try {
            i++; // 1
            i = 1 / 0; // 算术异常
            return i;
      } catch (Exception e) {
            System.exit(0); // 退出程序
      } finally {
            System.out.println("here is finally"); // finally不会执行
      }

      return 0;
    }
}3.异常抛出

1.自动抛出异常
当方法中出现异常,会自动创建一个对应的异常类对象。比如:数组越界就是 ArrayIndexOutOfBoundsException;空指针就是 NullPointerException。
2.手动抛出异常
开发人员可以在程序中通过 throw 关键字手动抛出异常。比如:在 catch 中手动抛出异常停止程序;个人学习、调试中手动抛出异常模拟程序异常。

[*]throw 关键字:throw 表示一种动作,可以用于抛出异常,在方法体中使用。
[*]throws 关键字:大家应该还见过 throws,放在方法头上,后面可以接多个异常类。throws 用来声明异常,若方法中存在编译时异常(非运行时异常),如果不对其捕获,则必须在方法头中显式声明该异常,以便于告知方法调用者此方法可能出现异常。
4.异常处理

java 异常处理遵循捕获、处理、传递的原则。当异常发生时,首先尝试在当前方法中找到匹配的 catch 块进行处理。如果没有找到,异常会向上传递到调用该方法的上级方法,直到找到匹配的 catch 块或者到达顶层被 jvm 处理。
如果一个异常在产生后没有被任何代码处理,它会被抛给 jvm。jvm 会终止当前线程,并打印出异常的堆栈跟踪信息。
在调用方法时,jvm 会将方法压入栈中,当方法执行完毕,会从栈顶弹出。当异常发生时:

[*]jvm 尝试在当前方法内部找到可以处理异常的程序(catch 代码块)
[*]若当前方法中没有捕获异常,则该异常会被传递到这个方法的调用者
[*]循环过程:jvm 尝试在方法内部找到处理异常的程序,否则继续传递给方法调用者
[*]当异常被传递到最顶级(最底层)的方法,而这个方法也没有办法处理这个异常,则该异常会被 jvm 处理:

[*]打印异常信息
[*]停止程序(非正常停止)

5.自定义异常类

其实 java 已经内置了很多详细的异常类了。但是,在实际开发过程中,根据业务的要求,会出现一些跟业务相关的异常,需要程序员自己定义。
一个最基本的异常类应包含两个构造函数:无参构造函数和详细描述信息构造函数,这个异常类就已经可以使用了。
如果还有其他需求,可以在类中添加属性和方法实现。
// 如果是运行时异常,就继承RuntimeException,如果是编译时异常就继承Exception
public class UserNotFoundException extends RuntimeException{
    // 空参构造
    public UserNotFoundException() {
      super();
    }

    // 带参构造,message就是异常的提示信息
    public UserNotFoundException(String message) {
      super(message);
    }
}
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

阙忆然 发表于 6 天前

分享、互助 让互联网精神温暖你我
页: [1]
查看完整版本: java 异常处理