3.1java的异常

    技术2022-07-17  72

    前言: java程序运行中难免会有异常出现,一些由用户造成,一些由随机因素造成,为了处理这些异常,java内置了一套遗产机制。 java中的异常是class 借鉴图片: 由图知其有两种异常: 第一种是:Error,表示严重的错误,程序对此无能无力。 第二种是:Exception,运行的错误,表示可以被捕获并处理。

    我们经常使用的异常处理就是Exception Exception分为两种:

    RuntimeException以及它的子类;非RuntimeException(包括IOException、ReflectiveOperationException等等)

    java中又分为需要捕获和不需要捕获的异常:

    必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。

    捕获异常

    捕获异常使用try…catch语句,把可能发生异常的代码放到try {…}中,然后使用catch捕获对应的Exception及其子类:

    public class Main { public static void main(String[] args) { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); } static byte[] toGBK(String s) { try { // 用指定编码转换String为byte[]: return s.getBytes("GBK"); } catch (UnsupportedEncodingException e) { // 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException: System.out.println(e); // 打印异常信息 return s.getBytes(); // 尝试使用用默认编码 } } }

    可以使用多个catch语句:

    可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。 存在多个catch情况时,catch的顺序十分重要,子类需要放在前面,否则永远也匹配不到子类。

    public static void main(String[] args) { try { process1(); process2(); process3(); } catch (IOException e) { System.out.println(e); } catch (NumberFormatException e) { System.out.println(e); } }

    finally语句

    无论是否捕捉到异常,都执行的语句

    public static void main(String[] args) { try { process1(); process2(); process3(); } catch (UnsupportedEncodingException e) { System.out.println("Bad encoding"); } catch (IOException e) { System.out.println("IO error"); } finally { System.out.println("END"); } }

    finally的特点:

    finally可写可不写finally总是最后执行

    捕获多种异常

    由于某些情况下,两个异常的处理方式相同,则可以用‘|’将两个异常连接起来。

    catch (IOException | NumberFormatException e) { // IOException或NumberFormatException System.out.println("Bad input");

    抛出异常

    打印方法调用栈:printStackTrace()方法,在抛出异常时,能够明确的看到抛出异常最初是在哪里抛出的。

    throw语句:异常正常抛出的示例

    void process2(String s) { if (s==null) { throw new NullPointerException();//在这里抛出异常 } }

    异常转换:

    ```java public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } } static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(); } } static void process2() { throw new NullPointerException(); } } ``` - 解释:上述代码中,执行main方法调用process1方法,process1方法调用process2方法抛出NullPointerException异常,process2方法没有捕获,抛往上层方法process1方法,process1方法捕获到空指针异常之后,重新抛出IllegalArgumentException()异常,接着被上层main方法捕获。 - 异常栈为:异常栈按顺序打印被捕获到的异常。 ```bash java.lang.IllegalArgumentException at Main.process1(Main.java:15) at Main.main(Main.java:5) ``` 如果抛出异常,不会影响finally的执行。jvm会先执行finally语句,然后抛出异常。

    异常追踪

    在上述代码中,异常栈中,只是指出了很浅显的异常,并没有指出最根本的原因,如何用其找到最根本的原因。 将上述代码中process2中捕获到异常后抛出异常的部分修改为:throw new IllegalArgumentException(e); 上述代码异常栈多出了Caused by的部分,这里才是最根本的原因。

    java.lang.IllegalArgumentException: java.lang.NullPointerException at Main.process1(Main.java:15) at Main.main(Main.java:5) Caused by: java.lang.NullPointerException at Main.process2(Main.java:20) at Main.process1(Main.java:13)

    异常屏蔽

    但如果程序出现异常之后,finally在执行中又出现异常,那么最先开始的异常会被屏蔽,进而只抛出最后一个异常,也就是finally中抛出的异常。如何解决?一般情况下,我们会把所有的异常存放在origin中,并在finally中判断其是否为空,不为空则打印异常信息。 public class Main { public static void main(String[] args) throws Exception { Exception origin = null; try { System.out.println(Integer.parseInt("abc")); } catch (Exception e) { origin = e;//将异常存储在origin中 throw e; } finally { Exception e = new IllegalArgumentException(); if (origin != null) {//在这里判断是否之前存在异常 e.addSuppressed(origin); } throw e; } } }

    自定义异常

    一般来说,java给出的常用异常已经够基本开发使用,但一些大型项目中需要自定义异常,最常见的做法是自定义一个BaseException作为根异常(继承自RuntimeException),并且自定义的BaseException应该提供多个构造方法。

    public class BaseException extends RuntimeException { public BaseException() { super(); } public BaseException(String message, Throwable cause) { super(message, cause); } public BaseException(String message) { super(message); } public BaseException(Throwable cause) { super(cause); } }

    NullPointerException(空指针异常)

    指针在java中不存在,说法是从C语言中流传过来的,正常的说法应该是空引用。 NullPointerException是常见的错误,应早暴露早修复 避免空指针异常:应用""空字符串或空数组。 java14开始JVM可以告诉我们详细的出错信息,告诉我们Null对象是谁。

    Processed: 0.008, SQL: 10