【Java】异常处理

Java异常

抛出异常

抛出异常分两步:

  1. 创建某个Exception实例

  2. throw语句抛出

知识点:当一个异常被抛出后,如果被别的方法捕获后又抛出了另一个异常,那就看不到原始异常了:当process2()抛出NullPointerException后,被process1()捕获,然后抛出IllegalArgumentException(),那新的异常丢失了原始异常信息,就看不到原始异常NullPointerException的信息了。

为了能追踪到完整的异常栈,在构造异常的时候,把原始的Exception实例传进去,新的Exception就可以持有原始Exception信息,如下面代码的throw new IllegalArgumentException(e)

public class Main {
    public static void main(String[] args) {

        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace(); //可以打印异常的传播栈,对于调试非常有用
        }finally {
            System.out.println("End...");
        }

    }

    static void process1(){
        try {
            process2();
        }catch (NullPointerException e){
            throw new IllegalArgumentException(e); //抛出两个异常
        }
    }

    static void process2(){
        throw new NullPointerException();
    }
}

自定义异常

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

BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生,并且应提供多个构造方法:

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

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

public class UserNotFoundException extends BaseException {
}

public class LoginFailedException extends BaseException {
}

...

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

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

日志

1. JDK Logging

配置不太方便,需要在JVM启动时传递参数-Djava.util.logging.config.file=

Java标准库内置了日志包java.util.logging

JDK的Logging定义了7个日志级别,从严重到普通,INFO级别以下的日志不会被打印出:

  • SEVERE
  • WARNING
  • INFO(默认)
  • CONFIG
  • FINE
  • FINER
  • FINEST
Logger logger = Logger.getGlobal();
logger.info("start process...");
logger.warning("memory is running out...");
logger.fine("ignored."); //不会被打印出
logger.severe("process will be terminated...");
2. Commons Logging

Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging。

Commons Logging定义了6个日志级别:

  • FATAL:非常严重的错误
  • ERROR:错误
  • WARNING:警告
  • INFO(默认)
  • DEBUG:调试信息
  • TRACE:更底层的调试信息

使用Commons Logging只需要和两个类打交道,并且只有两步:

  1. 通过LogFactory获取Log类的实例;
  2. 使用Log实例的方法打日志。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Main {
    public static void main(String[] args) {
        Log log = LogFactory.getLog(Main.class);
        try {
            Integer.parseInt("abc");
        } catch (Exception e) {
            log.error("got exception!", e);
        }
    }

}

十月 10, 2019 11:18:43 下午 main.Main main
严重: got exception!
java.lang.NumberFormatException: For input string: “abc”
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at main.Main.main(Main.java:11)

导包步骤:

  1. 先去Apache官网[下载][https://commons.apache.org/proper/commons-logging/download_logging.cgi]org.apache.commons.logging
  2. commons-logging-1.2.jar放在工程的lib目录下
  3. 在IDEA中File –> Project Structure->Modules->Dependencies,点加号,选择jar包

注意:如果某个类是父类,那可以用getClass()替代Person.class

因为这样子类的log相当于LogFactory.getLog(Student.class),从父类继承而来,并且无需改动代码。

public class Person {
    protected final Log log = LogFactory.getLog(getClass());

    void foo() {
        log.info("foo");
    }
}
public class Student extends Person {
    void bar() {
        log.info("bar");
    }
}

你可能感兴趣的:(Java)