Java的异常
- 异常是一种class, 本身带有类型信息
- 异常可以在任何地方抛出, 但只需要在上层捕获
- 最先来自于
Throwable
, 分为Error
和Exception
- Error: 严重错误, 系统无能力处理
OutOfMemoryError
: 内存溢出异常
NoClassDefFoundError
: 无法加载class异常
StackOverflowError
: 栈溢出
- Exception: 运行时错误, 可以被捕获
NumberFormatException
: 数值类型的格式错误
FileNotFoundException
: 未找到文件
SocketException
: 读取网络失败
NullPointerException
: 空指针异常
IndexOutOfBoundsException
: 数组索引越界
- Exception分成:
- RuntimeException以及它的子类
- 非RuntimeException(包括 IOException, ReflectiveOperationException)
- 必须捕获的异常(Checked Exception): Exception及其子类, 不包括
RuntimeException
- 不需要捕获的: Error及其子类, 以及
RuntimeException
捕获异常(java的异常)
- 定义的时候, 进行throws, 表示可能抛出的类型
- 可能抛出的异常, 都必须捕获
- 所有的异常, 最终在main()中捕获, 不会出现漏写的情况
public static void main(String[] args) throws Exception {
: main
方法可以抛出所有异常, 但一旦抛出, 程便终止运行
- 异常要有最基本的处理:
e.printStackTrace()
打印异常栈
捕获异常
- 可以同时捕获 多个语句
- catch语句, 可以进行不同类型的捕获
- catch的顺序非常重要, 子类必须在前面
finally
- 保证有无错误, 都会执行
- 不是必须的, 可写可不写
- 总是在最后执行
- 某些情况下, 可以没有
catch
, 直接使用finally
进行捕获, 但是就要声明可能抛出的异常
捕获多种异常
- 多条相同
catch
可以一起实现
} catch ( IOException | NumberFormatException e ) {
抛出异常
- 异常不断向上抛出, 直到被捕获
- 捕获后再抛出其他类型的, 进行类型转换
- 为了保存异常信息: 需要将原始Exception实例传进去
Throwable.getCause()
: 获取原始异常
- 异常抛出, 不影响finally执行, jvm优先执行finally
- finally也抛出异常, 就会把catch中的异常屏蔽
自定义异常
- 自定义一个
baseException
作为根异常
- 建议根异常从
RuntimeException
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);
}
}
class UserNotFoundException extends BaseException {
}
class LoginFailedException extends BaseException {
}
使用断言
- 断言自动忽略, 使用
enableassertions
进行启用
java -ea Main.java
-ea:com.itranswarp.sample.Main
: com.itranswarp.sample.Main
这个类使用断言
-ea:com.itranswarp.sample...
: com.itranswarp.sample
这个包使用断言
- 断言很少被使用, 更好的方法是使用单元测试
使用JDK Logging
- 日志替代
System.out.println
- 日志分成各个级别
使用Common Logging
- 在静态方法中使用Log, 通常定义一个静态类型变量
public class Main {
static final Log log = LogFactory.getLog(Main.class);
static void foo() {
log.info("foo");
}
}
public class Person {
// 使用getClass() 子类可以直接使用该log
protected final Log log = LogFactory.getLog(getClass());
void foo() {
log.info("foo");
}
}
- 提供重载方法
info(String, Throwable)
进行日志记录
使用Log4j
- 组件化的日志系统
- 通过不同的
Appender
输出到不同的目的地
- 通过
Filter
来进行需要输出哪些日志
- 通过
Layout
进行格式化信息
- 并不关心API, 使用配置文件
- 开发阶段使用
使用SLF4J和Logback
疑问
- 同时抛出两种类型的异常怎么办: 猜测, 抛出异常的父类即可