7 异常、断言和日志

在 Java 中,如果某个方法不能够采用正常的途径完整它的任务,就可以通过另外一个路径退出方法。

在这种情况下,将会立刻退出,并不返回任何值,而是抛出(throw)一个封装了错误信息的对象。

此外,调用这个方法的代码也将无法继续执行,取而代之的是异常处理机制开始搜索能够处理这种异常状况的异常处理器。

7.1 处理错误

所有的异常都是由 Throwable 继承而来,并分为两个分支:ErrorException

Error 类继承链描述了 Java 运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。这种情况很少出现。

Exception 继承链分为两个分支:由程序错误导致的异常属于RuntimeException

而程序本身没有问题,但由于像 I/O 错误这类问题导致的异常属于其他异常

Java 语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为非受查(unchecked)异常,所有其他的异常称为受查(checked)异常。

编译器将核查是否为所有的受査异常提供了异常处理器。

一个方法必须声明所有可能抛出的受查异常 ,而非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。

如果方法没有声明所有可能发生的受查异常,编译器就会发出一个错误消息。

如果在子类中覆盖了超类的一个方法,子类方法中声明的受查异常不能比超类方法中声明的异常更通用。

如果超类方法没有抛出任何受查异常,子类也不能抛出任何受查异常。

7.2 捕获异常

7.2.1 捕获一个异常

  1. try / catch 处理
  2. throws 传递出去

7.2.2 捕获多个异常

try {
code that might throw exceptions
}
catch (FileNotFoundException e) {
emergency action for missing files
}
catch (UnknownHostException e) {
emergency action for unknown hosts
}
catch (IOException e) {
emergency action for all other I/O problems
}
/// 第一个异常变量 e 隐含为 final 变量
try {
code that might throw exceptions
}
catch (FileNotFoundException | UnknownHostException e) {
emergency action for missing files and unknown hosts
}
catch (IOException e) {
emergency action for all other I/O problems
}

7.2.3 再次抛出异常与异常链

可以在 catch 里再抛出异常,这样做的目的是改变异常的类型:

try {
access the database
}
catch (SQLException e) {
throw new ServletException("database error: " + e.getMessage());
}

更好的处理办法是将原始异常设置为新异常的“原因”:

try {
access the database
}
catch (SQLException e) {
Throwable se = new ServletException("database error");
se.initCause(e);
throw se;
}
// 这样一来,可以使用下面这条语句重新得到原始异常:
Throwable e = se.getCause()

7.2.4 finally 子句

try 语句可以只有 finally 子句,而没有 catch 子句。

  • finally 执行的几种情况

  • try/catch 和 try/finally 解耦合。里面的 try 语句块只确保输入流被关闭;

    外面的 try 语句块只确保报告出现的错误;同时也会报告 finally 子句中出现的错误。

InputStream in = . . .;
try {
try {
code that might throw exceptions
}
finally {
in.close();
}
}
catch (IOException e) {
show error message
}

7.2.5 带资源的 try 子句

try (Scanner in = new Scanner(new FileInputStream("/usr/share/dict/words"), "UTF-8");
PrintWriter out = new PrintWriter("out.txt"))
{
while (in.hasNext())
out.println(in.next().toUpperCase());
}

不论这个块如何退出,in 和 out 都会关闭,就好像使用了 finally 块一样。

之前,如果 try 块抛出一个异常,而且 close 方法也抛出一个异常,这就会带来一个难题。带资源的 try 语句可以很好地处理这种情况。

原来的异常会重新抛出,而 close 方法抛出的异常会“被抑制”。这些异常将自动捕获,并由 addSuppressed 方法增加到原来的异常。

如果对这些异常感兴趣,可以调用 getSuppressed 方法,它会得到从 close 方法抛出并被抑制的异常列表。

7.2.6 分析堆栈轨迹元素

堆栈轨迹(stack trace)是一个方法调用过程的列表,它包含了程序执行过程中方法调用

的特定位置。

Throwable t = new Throwable();
t.printStackTrace();
StackTraceElement[] frames = t.getStackTrace();
///
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
for (Thread t : map.keySet())
{
StackTraceElement[] frames = map.get(t);
analyze frames
}

7.3 使用异常机制的tips(略)

7.4 使用断言(暂略)

7.5 记录日志

logging API 解决频繁插入/删除 System.out.println 的问题。

以下仅介绍简单使用:

// Logger log = Logger.getLogger("name");
Logger global = Logger.getGlobal();
global.info("this is a message");
global.setLevel(Level.OFF);

通常有7个日志级别:

SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST

每个级别有对应的记录方法:

logger.warning("message");
logger.fine("message");
...
logger.log(Level.WARNING, "message");
logger.log(Level.FINE, "message");
...

设置日志对象记录的级别。默认日志级别为 INFO,可以记录 INFO 与更高的两个级别的日志。

logger.setLevel(Level.FINE);
...
logger.setLevel(Level.ALL); //开启所有级别的记录
logger.setLevel(Level.OFF); //关闭所有级别的记录

更高级的日志使用暂略。常用日志框架有Commons-loggingSlf4jlog4j等。

7.6 调试技巧(暂略)

这部分以后可能会补上

【阅读笔记】Java核心技术卷一 #5.Chapter7的更多相关文章

  1. 【阅读笔记】Java核心技术卷一 #0

    这是一篇备忘性质的读书笔记,仅记录个人觉得有用的知识点 本文作为一个目录索引,部分章节跳过 吐槽:此书中文翻译有不少地方不太通顺,这种情况我要把英文版对应的部分也读一遍才能明白(说实话,英文里的从句表 ...

  2. java核心技术卷一

    java核心技术卷一 java基础类型 整型 数据类型 字节数 取值范围 int 4 +_2^4*8-1 short 2 +_2^2*8-1 long 8 +_2^8*8-1 byte 1 -128- ...

  3. 对《Java核心技术卷一》读者的一些建议

    <Java核心技术卷一>是唯一可以和<Java编程思想>媲美的一本 Java 入门书.单从技术的角度来看,前者更好一些.但上升到思想层面嘛,自然后者更好,两者的偏重点不同. 思 ...

  4. 读《java核心技术卷一》有感

    过去一个多月了吧.才囫囵吞枣地把这书过了一遍.话说这书也够长的,一共706页.我从来不是个喜欢记录的人,一直以来看什么书都是看完了就扔一边去,可能有时候有那么一点想记录下来的冲动,但算算时间太紧,很多 ...

  5. 【阅读笔记】Java核心技术卷一 #6.Chapter8

    8 泛型程序设计 8.1 为什么要使用泛型程序设计 类型参数(type parameters)(E.T.S...) 通配符类型(wildcard type)(?) 注意这两者用法用处并不同. 8.2 ...

  6. 【阅读笔记】Java核心技术卷一 #4.Chapter6

    6 接口.lambda 表达式与内部类 6.1 接口 6.1.1 接口概念 接口绝不能含有实例域:但在接口中可以定义常量,被自动设为 public static final 接口中的所有方法自动地属于 ...

  7. 【阅读笔记】Java核心技术卷一 #3.Chapter5

    5 继承 5.1 类.超类和子类 5.1.1 定义子类 超类(superclass)和子类(subclass), 基类(base class)和派生类(derived class), 父类(paren ...

  8. 【阅读笔记】Java核心技术卷一 #2.Chapter4

    4 对象和类 4.1 面向对象程序设计概述(略) 4.2 使用预定义类 java.time.LocalDate static LocalDate now(); static LocalDate of( ...

  9. 【阅读笔记】Java核心技术卷一 #1.Chapter3

    3 Java的基本程序设计结构 3.1 一个简单的 Java 应用程序(略) 3.2 注释(略) 3.3 数据类型 8种基本类型 byte,short,int,long float,double ch ...

随机推荐

  1. Qt中的多线程与线程池浅析+实例

    1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...

  2. 在VScode 中使用RT-Thread Studio初体验

    前言 工欲善其事,必先利其器,VScode是什么东东,想必大家都非常熟悉了,丰富的插件,有好的开发界面,是很多程序开发者的不二之选,RT-Thread竟然也开发了Vscode插件,真的是非常的nice ...

  3. Git操作文档

    Git 操作文档 Git 是一个十分流行的版本控制系统,Git 和 SVN 区别在于,SVN使用增量文件系统,存储每次提交之间的差异.而 git 使用全量文件系统,存储每次提交的文件的全部内容(sna ...

  4. kafka基础知识梳理

    一.Kafka的基本概念 关键字: 分布式发布订阅消息系统:分布式的,分区的消息服务 Kafka是一种高吞吐量的分布式发布订阅消息系统,使用Scala编写. 对于熟悉JMS(Java Message ...

  5. Java安全之Weblogic内存马

    Java安全之Weblogic内存马 0x00 前言 发现网上大部分大部分weblogic工具都是基于RMI绑定实例回显,但这种方式有个弊端,在Weblogic JNDI树里面能将打入的RMI后门查看 ...

  6. Redis的数据安全与性能保障

    1.持久化选项 Redis提供了2种不同的持久化方法来将数据存储到硬盘里面.一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里.另一种方法叫只追加文件(appen ...

  7. Linux云计算-03_必备基础命令

    Linux系统启动默认为字符界面,一般不会启动图形界面,所以对命令行的熟练程度能更加方便.高效的管理Linux系统. 本章介绍Linux系统必备命令各项参数及功能场景,Linux常见命令包括:cd.l ...

  8. Activiti7 入门篇

    1.  工作流 简单地来讲,工作流就是在计算机的协助下实现流程的自动化控制.目前,笔者熟知的主流的框架有:Camunda .Flowable .Activiti .jBPM.还有我们国产的盘古BPM. ...

  9. 【译】GO语言:管理多个错误

    原文:https://medium.com/a-journey-with-go/go-multiple-errors-management-a67477628cf1 ​ 关于开发者使用Go遇到的最大挑 ...

  10. 【译】在运行时编辑代码的 .NET 热重载

    今天,我们很高兴向你介绍 Visual Studio 2019 中 16.11(预览版1)中的 .NET 热重载(通过 .NET 6(预览版4)中的 dotnet watch 命令行工具).在这篇文章 ...