zoukankan      html  css  js  c++  java
  • [Java 学习笔记] 异常处理

    目录

    异常的类别

    异常的捕获与抛出

    打印出方法的调用栈 

    示例1:

    示例2:

    注意

    自定义异常


    总结自廖雪峰老师的Java教程: Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)icon-default.png?t=L9C2https://www.liaoxuefeng.com/wiki/1252599548343744


    异常的类别

    Error表示严重的错误,程序对此一般无能为力,例如:

    • OutOfMemoryError:内存耗尽
    • NoClassDefFoundError:无法加载某个Class
    • StackOverflowError:栈溢出

    Exception则是运行时的错误,它可以被捕获并处理, 分为两大类:

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

    不需要捕获的异常,包括Error及其子类,RuntimeException及其子类,

    编译器对RuntimeException及其子类不做强制捕获要求,不是指应用程序本身不应该捕获并处理RuntimeException。是否需要捕获,具体问题具体分析

    异常的捕获与抛出

    多个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);
        }
    }
    

    存在多个catch的时候,catch的顺序非常重要:子类必须写在前面。例如:

    public static void main(String[] args) {
        try {
            ...
            ...
        } catch (IOException e) {
            System.out.println("IO error");
        } catch (UnsupportedEncodingException e) { // 永远捕获不到
            System.out.println("Bad encoding");
        }
    }
    

    UnsupportedEncodingException异常捕获不到,因为它是IOException的子类。当抛出UnsupportedEncodingException异常时,会被catch (IOException e) { ... }捕获并执行。

    正确的写法是把子类放到前面:

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

    打印出方法的调用栈 

    通过printStackTrace()可以打印出方法的调用栈 

    示例1:

    public class Main {
        public static void main(String[] args) {
            try { 
                process1();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        static void process1() {
            process2();
        }
    
        static void process2() {
            Integer.parseInt(null); // 会抛出NumberFormatException
        }
    }

     

    从下往上看, 调用层级关系

    main()   process1()    process2() 

      Integer.parseInt(String)    Integer.parseInt(String, int)

    查看Integer.java源码可知,抛出异常的方法代码如下:

     

    示例2:

    public class demo {
        public static void main(String[] args) {
            try {
                process1();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        static void process1() {
            try {
                process2();
            } catch (NullPointerException e) {
                throw new IllegalArgumentException(e);
            }
        }
    
        static void process2() {
            throw new NullPointerException();
        }
    }
    

     由Caused by: java.lang.NullPointerException可知,问题的根源在于Main.process2()方法抛出的NullPointerException

    注意

    • 在代码中获取原始异常可以使用Throwable.getCause()方法。如果返回null,说明已经是“根异常”了
    • 捕获到异常并再次抛出时,一定要留住原始异常,否则很难定位第一案发现场
    • catch中抛出异常,不会影响finally的执行。JVM会先执行finally,然后抛出异常    (若是finally中抛出了异常, catch所捕捉到的异常便会丢失, 像是中途被调包了似的, 这叫做异常屏蔽)

    自定义异常

    (引用自自定义异常 - 廖雪峰的官方网站)

    保持一个合理的异常继承体系

    一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。

    BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生:

    public class BaseException extends RuntimeException {
    }
    

    其他业务类型的异常就可以从BaseException派生:

    public class UserNotFoundException extends BaseException {
    }
    
    public class LoginFailedException extends BaseException {
    }
    
    ...
    

    自定义的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);
        }
    }
    

    上述构造方法实际上都是原样照抄RuntimeException。这样,抛出异常的时候,就可以选择合适的构造方法。通过IDE可以根据父类快速生成子类的构造方法。

  • 相关阅读:
    弄清变量名字空间
    Perl中文编码的处理
    了解魔符的含义
    Log::Minimal 小型可定制的log模块
    Perl – 文件测试操作符
    在源代码中使用Unicode字符
    editplus乱码charset的奇怪问题
    ASP.NET程序中常用代码汇总(一)
    ASP.NET程序中常用代码汇总(三)
    ASP.NET程序中常用代码汇总(二)
  • 原文地址:https://www.cnblogs.com/Knight02/p/15799058.html
Copyright © 2011-2022 走看看