b1cat`s

Java异常处理

Word count: 882Reading time: 3 min
2020/02/13

Java异常处理

讨论如何在Java中处理各种异常情况

Java内置了一套异常处理机制,总是用异常来表示错误。异常是一种class,因此它本身带有类型信息。

image-20200213181717923

  • Throwable有两个体系,ErrorExceptionError表示严重的错误,程序无能为力。

    • OutOfMemoryError 内存耗尽
    • NoClassDefFoundError被定义
    • StackOverflowError栈溢出
  • 而Exception是可以被捕获处理的

    • 某些异常是应用处理的一部分:如
      • 数值类型的格式错误 NumberFormatException
      • 未找到文件FileNotFoundException
      • 网络访问失败SocketException
    • 程序编写逻辑不对
      • 对Null的对象调用方法或字段NullPointerException
      • 数组索引越界IndexOutOfBoundsException
  • Exception分为两类

    • RuntimeException以及它的子类
    • RuntimeException
  • 必须捕获的异常非RuntimeException及其子类

1
2
3
4
5
try{
//do something
}catch (Exception e){
e.printStackTrace();//打印调用栈
}
  • 懒得写try…catch..可以直接在main函数
    public static void main(String[] args) throws Exception

捕获异常

多catch语句,只有一个catch被执行,且子类异常必须在父类异常前面,否则不会被子类异常捕获到。

1
2
3
4
5
6
7
try{
process1();
} catch (UnsupportedEncodingException e){ //为IOException的子类
System.out.println("Bad encoding");
} catch (IOException e){
System.out.println("IO error);
}
  • 使用finally语句确保有无错误都会执行

抛出异常

1
2
3
4
5
6
void process2(String s){
if(s=null){
NullPointerException e = new NullPointerException();
throw e;
}
}
  • 抛出异常1.创建异常 ``2用throw抛出
  • 上述抛出异常简写throw new NullPointerException()
  • 先执行finally然后在抛出catch中的异常
  • 优先finally抛出异常,调用栈中存在catch中的异常
  • 通过Throwable.getSuppressed()可以获取所有的Suppressed Exception

自定义异常

常用异常
image-20200213181741772

在需要自定义异常时,保持合理的异常继承体系很重要。
常见做法是自定义一个BaseException作为根异常,然后派生出各种业务类型的异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//BaseException 
//继承RuntimeException 构造方法参考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 LoginFiledException extends BaseException{}
//...

使用断言Assert

  • 断言是一种调试方式,断言失败会抛出AssertionError,只能在开发和测试阶段启用断言;
  • 语句assert x >= 0;即为断言,断言条件x >= 0预期为true。如果计算结果为false,则断言失败,抛出AssertionError
  • 使用断言需要JVM启用断言,传递-enableassertions(可简写为-ea)参数
  • 对可恢复的错误不能使用断言,而应该抛出异常;
  • 断言很少被使用,更好的方法是编写单元测试。

使用JDK Longging替代print检查

Java内置了java.util.logging,可以直接使用

1
2
3
4
5
6
7
8
Logging定义了7个日志级别,从严重到普通:
SEVERE
WARNING
INFO //默认级别,以下不会被打印
CONFIG
FINE
FINER
FINEST

需要JVM启动时传递参数-Djava.util.logging.config.file=<config-file-name>

使用第三方库

Commons Logging

可以挂接不同的日志系统,默认自动搜索使用Log4j,如果没有Log4j,再使用JDK Logging
使用方法:

  • 通过LogFactory获取Log类的实例
  • 使用Log实例的方法打印
  • 需要下载导入
1
2
3
Log log = LogFactory.getLog(Main.class);
log.info("start log ...");
log.warn("end .")

log4j

image-20200213181810366

SLF4J和Logback

拼字符串是一个非常麻烦的事情,所以SLF4J的日志接口改进成这样了:一个带占位符的字符串,用后面的变量自动替换占位符。
使用方法和Commons Logging一样

CATALOG
  1. 1. Java异常处理
    1. 1.0.1. 捕获异常
    2. 1.0.2. 抛出异常
    3. 1.0.3. 自定义异常
    4. 1.0.4. 使用断言Assert
    5. 1.0.5. 使用JDK Longging替代print检查
    6. 1.0.6. 使用第三方库
      1. 1.0.6.1. Commons Logging
      2. 1.0.6.2. log4j
      3. 1.0.6.3. SLF4J和Logback