zoukankan      html  css  js  c++  java
  • Java异常处理基础知识笔记:异常处理机制、异常继承关系、捕获异常、抛出异常、异常的传播、异常调用栈、自定义异常、第三方日志库

    一、Java中的异常

    1、Java内置了一套异常处理机制,总是使用异常来表示错误。异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了

    2、Java异常的继承关系

      从继承关系可知:Throwable是异常体系的根,它继承自ObjectThrowable有两个体系:ErrorExceptionError表示严重的错误,程序对此一般无能为力。如:

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

      而Exception则是运行时的错误,它可以被捕获并处理。某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:

    • NumberFormatException:数值类型的格式错误
    • FileNotFoundException:未找到文件
    • SocketException:读取网络失败

      还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:

    • NullPointerException:对某个null的对象调用方法或字段
    • IndexOutOfBoundsException:数组索引越界

      Exception又分为两大类:

    (1)RuntimeException以及它的子类;

    (2)非RuntimeException(包括IOExceptionReflectiveOperationException等等)

    3、Java规定:

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

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

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

    5、在方法定义的时候,使用throws Xxx表示该方法可能抛出的异常类型。调用方在调用的时候,必须强制捕获这些异常,否则编译器会报错。

    6、只要是方法声明的Checked Exception,不在调用层捕获,也必须在更高的调用层捕获。所有未捕获的异常,最终也必须在main()方法中捕获,不会出现漏写try的情况。这是由编译器保证的。main()方法也是最后捕获Exception的机会。

    7、不推荐捕获了异常但不进行任何处理。所有异常都可以调用printStackTrace()方法打印异常栈,这是一个简单有用的快速打印异常的方法。

    二、捕获异常

    1、可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。简单地说就是:多个catch语句只有一个能被执行。

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

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

      对于上面的代码,UnsupportedEncodingException异常是永远捕获不到的,因为它是IOException的子类。当抛出UnsupportedEncodingException异常时,会被catch (IOException e) { ... }捕获并执行。因此,正确的写法是把子类放到前面。

    3、finally语句 —— finally是用来保证一些代码必须执行的

      无论是否有异常发生,如果我们都希望执行一些语句,例如清理工作,怎么写? —— Java的try ... catch机制还提供了finally语句,finally语句块保证有无错误都会执行。注意finally有几个特点:

    (1)finally语句不是必须的,可写可不写;

    (2)finally总是最后执行。

    4、捕获多种异常:如果某些异常的处理逻辑相同,但是异常本身不存在继承关系,那么就得编写多条catch子句,因为处理IOExceptionNumberFormatException的代码是相同的,所以我们可以把它两用|合并到一起。

    public static void main(String[] args) {
        try {
        } catch (IOException | NumberFormatException e) { // IOException或NumberFormatException
            System.out.println("Bad input");
        } catch (Exception e) {
            System.out.println("Unknown error");
        }
    }

    三、抛出异常

    1、异常的传播:当某个方法抛出了异常时,如果当前方法没有捕获异常,异常就会被抛到上层调用方法,直到遇到某个try ... catch被捕获为止。

    2、如何抛出异常?参考Integer.parseInt()方法,抛出异常分两步:实际上,绝大部分抛出异常的代码都会合并写成一行:throw new NullPointerException();

    // 1、创建某个Exception的实例
    NullPointerException e = new NullPointerException();
    
    // 2、用throw语句抛出
    throw e

    3、异常屏蔽:在finally里抛出异常后,原来在catch中准备抛出的异常就“消失”了,因为只能抛出一个异常。没有被抛出的异常称为“被屏蔽”的异常(Suppressed Exception)。

    四、自定义异常

    1、Java标准库定义的常用异常包括

    Exception
    │
    ├─ RuntimeException
    │  │
    │  ├─ NullPointerException
    │  │
    │  ├─ IndexOutOfBoundsException
    │  │
    │  ├─ SecurityException
    │  │
    │  └─ IllegalArgumentException
    │     │
    │     └─ NumberFormatException
    │
    ├─ IOException
    │  │
    │  ├─ UnsupportedCharsetException
    │  │
    │  ├─ FileNotFoundException
    │  │
    │  └─ SocketException
    │
    ├─ ParseException
    │
    ├─ GeneralSecurityException
    │
    ├─ SQLException
    │
    └─ TimeoutException

    2、在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。

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

    public class BaseException extends RuntimeException {
    }
    // 其他业务类型的异常就可以从BaseException派生:
    public class UserNotFoundException extends BaseException {
    }
    
    public class LoginFailedException extends BaseException {
    }

    4、自定义的BaseException应该提供多个构造方法:

    5、小结:

      抛出异常时,尽量复用JDK已定义的异常类型;

      自定义异常体系时,推荐从RuntimeException派生“根异常”,再派生出业务异常;

      自定义异常时,应该提供多种构造方法。

    五、NullPointerException

      NullPointerException即空指针异常,俗称NPE。如果一个对象为null,调用其方法或访问其字段就会产生NullPointerException,这个异常通常是由JVM抛出的。

      指针这个概念实际上源自C语言,Java语言中并无指针。我们定义的变量实际上是引用,Null Pointer更确切地说是Null Reference,不过两者区别不大。

    六、使用JDK Logging

      日志是为了替代System.out.println(),可以定义格式,重定向到文件等;

      日志可以存档,便于追踪问题;

      日志记录可以按级别分类,便于打开或关闭某些级别;

      可以根据配置文件调整日志,无需修改代码;

      Java标准库提供了java.util.logging来实现日志功能。

    七、第三方日志库

    1、Commons Logging 与 Log4j

      通过Commons Logging实现日志,不需要修改代码即可使用Log4j;

      使用Log4j只需要把log4j2.xml和相关jar放入classpath;

      如果要更换Log4j,只需要移除log4j2.xml和相关jar;

      只有扩展Log4j时,才需要引用Log4j的接口(例如,将日志加密写入数据库的功能,需要自己开发)。

    2、SLF4J和Logback

      SLF4J和Logback可以取代Commons Logging和Log4j;始终使用SLF4J的接口写入日志,使用Logback只需要配置,不需要修改代码。

  • 相关阅读:
    Mysql之存储过程与存储函数
    mysql-bin日志自动清理及手动删除
    mysql下面的binlog
    mysql下的数据备份与恢复
    查询mysql数据库中各个表所占空间大小以及索引大小
    mysql执行sql语句报错this is incompatible with sql_mode=only_full_group_by
    docker WARNING: IPv4 forwarding is disabled. 解决方法
    Linux平台修改环境变量的方式
    PuTsangTo
    (一) 从Angular1到Angular2的杂谈
  • 原文地址:https://www.cnblogs.com/goloving/p/14809667.html
Copyright © 2011-2022 走看看