《Java核心技术》阅读笔记(三)- 异常处理

JavaCoreNote–异常

如果由于出现错误而使得某些操作没有完成,程序应该:
• 返回到一种安全状态,并能够让用户执行一些其他的命令;或者
• 允许用户保存所有操作的结果,并以妥善的方式终止程序

异常

for:将控制权从错误产生的地方转移给能够处理这种情况的错误处理器

程序错误分类:

  1. 用户输入
  2. 物理限制
  3. 设备
  4. 代码
    处理方式:返回一个特殊的错误码;不返回任何值,而是抛出一个封装了异常信息的对象,寻找对应的错误处理器。

语法

分类
  • 非受查异常(unchecked)
    Error、RuntimeException
    Error类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误;
    RuntimeException:程序错误导致的异常,包括情况:

    • 错误的类型转换
    • 数组访问越界
    • 访问null指针
      如果出现RuntimeException异常,一定是程序员的问题
  • 受查异常(checked)
    非RuntimeException表示程序本身没有问题,但由于像IO错误这类的异常

何时声明
  1. 调用一个抛出受査异常的方法
  2. 程序运行过程中发现错误,并且利用throw语句抛出一个受查异常
  3. 程序出现错误抛出非受查异常
  4. 虚拟机和运行时库出现的内部错误

注:不应声明从Error继承来的错误、从RuntimeException继承来的异常

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

抛出异常
  1. 找到合适异常类
  2. 创建异常类对象
  3. 将对象抛出

定义异常类:派生于Exception或其子类的类,提供两个构造器
注:不允许子类的throws说明符中出现超过超类方法所列出的异常类范围

捕获异常
  • try/catch语句块
  • 何时捕获,何时抛出?——捕获哪些知道如何处理的异常
  • 捕获多个异常时,异常变量隐含为final变量
  • catch语句中可再次抛出异常,为了转换异常的类型,可设置异常原因initCause,getCause可重新获得
finally子句

for:资源回收问题,如果没有finally子句,一样的代码将在两个地方出现。
finally子句中包含return语句将覆盖try中的return

解耦合try/catch和try/finally语句块,内层负责关闭资源,外层负责确保报告出现的异常

InputStrean in = . . .;
try
{
    try
    {
        code that might throwexceptions
    }
    finally
    {
        in.cose(); 
    } 
}
catch (IOException e) {
    show error message
}

finally子句可能产生异常,覆盖原始的异常信息。

带资源的try语句
  • 资源属于实现AutoClosable接口的类,会自动调用close方法。
  • 带资源的try语句也可以有自己的catch、finally子句,这些子句会在调用了关闭资源之后执行。实际中,避免加入过多内容,很少这样使用这种情况。
    对于finally子句产生异常覆盖原始异常的问题,会自动调用addSuppressd方法添加到原始异常的抑制异常中,抛出原始异常,处理器可调用getSuppressed获得异常列表。
堆栈轨迹
  • Throwable.printStackTrace、getStackTrace
  • Thread.getAllStackTrace

使用技巧

  1. 异常处理不能代替简单测试
  2. 不要过分细化异常,使代码膨胀
  3. 利用异常层次结构
  4. 不要压制异常
  5. 检测错误时,苛刻比放任更好(早抛出)
  6. 不要羞于传递异常(晚捕获)

断言

for:有选择的启用检测

断言机制允许在测试期间向代码中插入一些检査语句。当代码发布时,这些插人的检测语句将会被自动地移走

使用

  1. assert 条件;
    assert 条件:表达式;
    条件不成立时抛出AssertionError异常,第二种形式中表达式生成一个说明字符串。

  2. 启用禁用
    不需要重新编译,是类加载器的功能。
    启用:-enableassertions 或 -ea
    可在某个类或包中启用:
    java -ea:MyClass -ea:com.mycompany.mylib… MyApp
    禁用:-disableassertions 或 -da

对于系统类(没有类加载器),使用:enablesystemassertions/-esa
程序中也可以控制,参看API

  1. 何时使用
  • 断言失败是致命的、不可恢复的错误;
  • 断言检查只用于开发和测阶段

日志

日志API优势:

  1. 很容易开启、取消全部或某个级别日志记录;
  2. 可以被定向到不同处理器;
  3. 记录器和处理器可以对记录过滤;
  4. 不同方式格式化;
  5. 可以用多个日志记录器;
  6. 默认用配置文件控制,也可用程序替换配置。

基本日志

  1. 调用全局记录器(global logger)
  2. 取消:Logger.getGlobal().setLevel(Off)

高级日志

  1. 记录器具有层次结构,子继承父的属性
  2. 7个级别:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST,默认前三个

默认记录类名、方法名信息,但VM可能进行优化得不到准确调用信息,可使用logp方法获得调用类和方法的确切信息

作用:

  1. 用来跟踪执行流的方法:entring、exiting
  2. 记录不可预料的异常:throwing、log

修改日志管理器配置

默认:jre/lib/1ogging.properties
修改:java -Djava.util.logging.config.file=configFile MainClass

修改日志级别 名称.level=FINE
默认日志管理器:java.util.logging.LogManager
可通过系统属性修改:java.util.logging.manager

处理器

  • 默认使用ConsoleHandler
  • 默认INFO级java.uti1.1ogging.ConsoleHandler.level
  • 默认发送到处理器及父处理器

其他处理器:FileHandler、SocketHandler
可修改文件处理器的默认行为

过滤器

实现Filter,记录器或处理器中setFilter方法使用

格式化

实现Formatter,处理器中setFormatter方法使用

常用操作

  1. 日志记录器命名为主程序包名
  2. 程序中安装默认配置
  3. 只将对用户有用的日志设置为前3个级别,显示在控制台。

调试技巧

  1. 打印变量;
  2. 在类中放置main方法,对每个类做单元测试;
  3. 使用JUnit组织测试用例
  4. 使用日志代理(logging proxy)截获方法调用,记录日志
  5. 打印堆栈轨迹Thread.dumpStack()
  6. 捕获堆栈轨迹到字符串
  7. 捕获错误信息到文件java MyProgram 2> errors.txt
    java MyProgram 1> errors.txt 2>&1
  8. 非捕获异常的堆栈轨迹保存到文件中,可以调用静态的 Thread.setDefaultUncaughtExceptionHandler方法改变非捕获异常的处理器
  9. 观察类的加载过程,可以用-verbose标志启动Java虚拟机
  10. -Xlint选项告诉编译器对一些普遍容易出现的代码问题进行检査
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vg4mJ7vS-1582984683851)(evernotecid://1520493E-927F-420A-8EE1-BA6F74088A9D/appyinxiangcom/11767354/ENResource/p3065)]
  11. 利用JVM对Java应用程序进行监控(monitoring)和管理 (management)的支持
    jconsole processID
  12. jmap实用工具获得一个堆的转储
    jmap -dump:format=b,file=dumpFileName processID
    jhat dumpFileName
    进人localhost:7000
  13. 使用 -Xprof 标志运行 Java 虚拟机, 就会运行一个基本的剖析器来跟踪那些代
    码中经常被调用的方法

小结

本文整理了程序错误的分类,除了返回特殊的返回值外,Java语言中可通过抛出异常对象、捕获异常的方式处理程序中出现的问题。通过不同日志级别记录程序运行中的业务、程序信息,通过断言实现程序开发、测试阶段的程序检测。

发布了159 篇原创文章 · 获赞 225 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/lyg673770712/article/details/104583090