1. 异常

  1. (P 280)异常处理需要考虑的问题:

    • 用户输入错误
    • 设备错误
    • 物理限制
    • 代码错误
  2. (P 280)传统的处理错误的方法是:返回一个特殊的错误码,常见的是返回-1或者null引用

  3. (P 280)在Java中,方法出现错误时,它会立即退出,不返回任何值,而是抛出一个封装了错误信息的对象

  4. (P 280)Java中所有的异常都是由Throwable继承而来,它下面又分解为两个分支:ErrorException

    • Error:描述了Java运行时系统的内部错误资源耗尽错误(对于处理这种错误,你几乎无能为力
    • Exception:又分解为两个分支:RuntimeException(由编程错误导致,如果出现该异常,那一定是你的问题)和其他异常(诸如IO错误这类问题)
      • 派生于RuntimeException的异常:

        • 错误的强制类型转换
        • 数组访问越界
        • 访问null指针
      • 不是派生于RuntimeException的异常:
        • 试图超越文件末尾继续读取数据
        • 试图打开一个不存在的文件
        • 试图根据特定的字符串查找Class对象,而这个字符串表示的类并不存在
    graph TD
    Throwable[Throwable]-->Error[Error]
    Throwable[Throwable]-->Exception[Exception]

    Error[Error]-->OtherError1[...]
    Error[Error]-->OtherError2[...]
    Error[Error]-->OtherError3[...]

    Exception[Exception]-->RuntimeException[RuntimeException]
    Exception[Exception]-->IOException[IOException]
    Exception[Exception]-->OtherException[...]

    IOException[IOException]-->OtherIOException1[...]
    IOException[IOException]-->OtherIOException2[...]
    IOException[IOException]-->OtherIOException3[...]

    RuntimeException[RuntimeException]-->OtherRuntimeException1[...]
    RuntimeException[RuntimeException]-->OtherRuntimeException2[...]
    RuntimeException[RuntimeException]-->OtherRuntimeException3[...]

  5. (P 281)派生于ErrorRuntimeException的所有异常称为非检查型异常,所有其他异常称为检查型异常

  6. (P 282)如果没有处理器捕获异常对象,那么当前执行的线程就会终止

  7. (P 283)必须在方法的首部列出所有检查型异常类型,但是不需要声明从Error继承的异常,也不应该声明从RuntimeException继承的那些非检查型异常

  8. (P 283)如果在子类中覆盖了超类的一个方法,子类方法中声明的检查型异常不能比超类方法中声明的异常更通用(子类方法可以抛出更特定的异常,或者根本不抛出任何异常)。如果超类方法没有抛出任何检查型异常,子类也不能抛出任何检查型异常

  9. (P 288)同一个catch子句中可以捕获多个异常类型,如果一些异常的处理逻辑是一样的,就可以合并catch子句。只有当捕获的异常类型彼此之间不存在子类关系时才需要这个特性

    1. try {
    2. ...
    3. } catch (FileNotFoundException | UnknownHostException e) {
    4. ...
    5. } catch (IOException e) {
    6. ...
    7. }
  10. (P 289)可以在catch子句中抛出一个异常,此时,可以把原始异常设置为新异常的“原因”

    1. try {
    2. ...
    3. } catch (SQLException original) {
    4. var e = new ServletException("database error");
    5. e.initCause(original);
    6. throw e;
    7. }

    捕获异常时,获取原始异常

    1. Throwable original = caughtException.getCause();
  11. (P 292)一种推荐的异常捕获写法:内层try语句块只有一个职责,就是确保释放资源外层try语句块也只有一个职责,就是确保报告出现的错误

    1. try {
    2. try {
    3. ...
    4. } finally {
    5. // 释放资源
    6. }
    7. } catch (Exception e) {
    8. // 报告错误
    9. }
  12. (P 293)Java 7中,对于实现了AutoCloseable接口的类,可以使用带资源的try语句(try-with-resources):

    1. try (Resources res = ...) {
    2. // Work with res
    3. ...
    4. }

    Java 9中,可以在try首部中提供之前声明的事实最终变量(effectively final variable):

    1. try (res) {
    2. // Work with res
    3. ...
    4. } // res.close() called here
  13. (P 294)在try-with-resources语句中,如果try块抛出一个异常,而且close方法也抛出一个异常,则原来的异常会重新抛出,而close方法抛出的异常会“被抑制”(可以通过getSuppressed方法得到这些被抑制的异常)

  14. (P 294)可以通过StackWalker类处理堆栈轨迹

    1. var walker = StackWalker.getInstance();
    2. walker.forEach(frame -> ...); // 例如:walker.forEach(System.out::println);
  15. (P 298)使用异常的一些技巧:

    • 异常处理不能代替简单的测试(捕获处理异常的成本很高,只在异常情况下使用异常
    • 不要过分的细化异常(有必要将整个任务包在一个try语句块中,将正常处理与错误处理分开
    • 充分利用异常层次结构
    • 不要压制异常(异常非常重要时,应该适当地进行处理)
    • 在检测错误时,“苛刻”要比放任更好
    • 不要羞于传递异常(最好继续传递异常,而不是自己捕获)

2. 断言

  1. (P 301)Java中引入了关键字assert,其有如下两种形式:

    1. assert condition;
    2. assert condition : expression;

    这两个语句都会计算条件,如果结果为false,则抛出一个AssertionError异常。在第二个语句中,表达式将传入AssertionError对象的构造器,并转换为一个消息字符串

  2. (P 301)默认情况下,断言是禁用的,可以使用-enableassertions或者-ea选项启用断言:

    1. java -enableassertions MyApp

    禁用断言可以使用-disableassertions-da

  3. (P 302)断言只应该用于在测试阶段确定程序内部错误的位置

3. 日志

  1. (P 305)基本日志的使用:

    • 生成简单的日志记录

      1. Logger.getGlobal().info("hello world!");
    • 取消所有日志

      1. Logger.getGlobal().setLevel(Level.OFF);
  2. (P 305)高级日志的使用:

    • 创建或获取日志记录器

      1. private static final Logger myLogger = Logger.getLogger("className"); // className是全限定类名
    • 设置日志级别

      1. logger.setLevel(Level.FINE); // FINE以及更高级别的日志都会被记录
    • 记录日志

      1. // 调用相应级别的日志记录方法
      2. logger.warning(message);
      3. logger.fine(message);
      4. // 使用log方法并指定级别
      5. logger.log(Level.FINE, message);
      6. // 跟踪执行流的方法
      7. logger.entering("className", "methodName", new Object[]{ params... });
      8. logger.exiting("className", "methodName", result);
      9. // 在日志记录中包含异常的描述
      10. logger.throwing("className", "methodName", exception);
      11. logger.log(Level.WARNING, message, exception);
  3. (P 305)7个日志级别:

    • SEVERE
    • WARNING
    • INFO
    • CONFIG
    • FINE
    • FINER
    • FINEST
  4. (P 307)可以通过配置文件修改日志系统的各个属性,默认情况下,配置文件位于:

    1. conf/logging.properties

    指定特定位置的配置文件:

    1. java -Djava.util.logging.config.file=configFile MainClass

    指定日志记录器的日志级别:在日志记录器名后面追加后缀.level,例如

    1. com.mycompany.myapp.level=FINE
  5. (P 313)日志技巧

    • 对一个简单的应用,选择一个日志记录器,可以把日志记录器命名为与主应用包一样的名字
    • 默认的日志配置会把级别等于或高于INFO的所有消息记录到控制台,用户可以覆盖这个默认配置,最好在你的应用中安装一个更合适的默认配置
    • 所有级别为INFO、WARNING和SEVERE的消息都将显示到控制台上
      • 只将对程序用户有意义的消息设置为以上这几个级别
      • 程序员想要的日志消息设定为FINE级别是一个很好的选择
  6. (P 321)调试技巧

    • 打印或日志记录变量的值

    • 在每一个类中放置一个单独的main方法,以便独立地测试类

    • 使用JUnit

    • 日志代理,它是一个子类的对象,可以截获方法调用,记录日志,然后调用超类中的方法

      1. var generator = new Random() {
      2. public double nextDouble() {
      3. double result = super.nextDouble();
      4. Logger.getGlobal().info("nextDouble: " + result);
      5. return result;
      6. }
      7. }
    • 利用Throwable类的printStackTrace方法,可以从任意的异常对象获得堆栈轨迹

    • 一般来说,堆栈轨迹显示在System.err上。如果想要记录或显示堆栈轨迹,可以将它捕获到一个字符串中

      1. var out = new StringWriter();
      2. new Throwable().printStackTrace(new PrintWriter(out));
      3. String description = out.toString();
    • 通常,将程序错误记入一个文件会很有用:

      1. java MyProgram > errors.txt # 错误,错误被发送到System.err而不是System.out
      2. java MyProgram 2> errors.txt # 正确,只输出System.err
      3. java MyProgram 1> errors.txt 2>&1 # 同时捕获System.out和System.err
    • 将未捕获的异常的堆栈轨迹记录到一个文件中,而不是直接输出到System.err,可以使用静态方法Thread.setDefaultUncaughtExceptionHandler改变未捕获异常的处理器

      1. Thread.setDefaultUncaughtExceptionHandler(
      2. new Thread.UncaughtExceptionHandler() {
      3. public void uncaughtException(Thread t, Throwable e) {
      4. // save information in log file
      5. }
      6. }
      7. )
    • 要想观察类的加载过程,启动Java虚拟机时可以使用-verbose标志

    • -Xlint选项告诉编译器找出常见的代码问题

      1. javac -Xlint sourceFiles
    • Java虚拟机增加了对Java应用程序的监控和管理支持,允许在虚拟机中安装代理来跟踪内存消耗、线程使用、类加载等情况。jconsole工具可以显示有关虚拟机性能的统计结果

    • Java任务控制器:一个专业级性能分析和诊断工具

《Java核心技术》笔记:第7章 异常、断言和日志的更多相关文章

  1. [core java学习笔记][第十一章异常断言日志调试]

    第11章 异常,断言,日志,调试 处理错误 捕获异常 使用异常机制的技巧 使用断言 日志 测试技巧 GUI程序排错技巧 使用调试器 11.1 处理错误 11.1.1异常分类 都继承自Throwable ...

  2. 20145330《Java学习笔记》第一章课后练习8知识总结以及IDEA初次尝试

    20145330<Java学习笔记>第一章课后练习8知识总结以及IDEA初次尝试 题目: 如果C:\workspace\Hello\src中有Main.java如下: package cc ...

  3. 【马克-to-win】学习笔记—— 第五章 异常Exception

    第五章 异常Exception [学习笔记] [参考:JDK中文(类 Exception)] java.lang.Object java.lang.Throwable java.lang.Except ...

  4. [core java学习笔记][第六章接口与内部类]

    接口域内部类 接口 描述类具有什么功能,不给出具体实现. 内部类 用于设计协作关系的类集合 代理 实现任意接口的对象. 6.1 接口 接口声明 public interface Comparable ...

  5. 初读"Thinking in Java"读书笔记之第二章 --- 一切都是对象

    用引用操纵对象 Java里一切都被视为对象,通过操纵对象的一个"引用"来操纵对象. 例如, 可以将遥控器视为引用,电视机视为对象. 创建一个引用,不一定需要有一个对象与之关联,但此 ...

  6. java核心技术笔记

    1.类和对象 第四章:面向对象 日历的作用是提供某个时间点的信息 查询设置信息:GregorianCalendar now = new GregorianCalendar() int month = ...

  7. Java 学习笔记 ------第三章 基础语法

    本章学习目标: 认识类型与变量 学习运算符的基本使用 了解类型转换细节 运用基本流程语法 一.类型(基本类型) 所谓基本类型,就是在使用时,得考虑一下数据用多少内存长度存比较经济,利用程序语法告诉JV ...

  8. Java 学习笔记 ------第四章 认识对象

    本章学习目标: 区分基本类型与类类型 了解对象与参考的关系 从打包器认识对象 以对象观点看待数组 认识字符串的特性 一."=" 和 "==" 当=用于基本类型时 ...

  9. Java 学习笔记 ------第五章 对象封装

    本章学习目标: 了解封装的概念与实现 定义类.构造函数与方法 使用方法重载与不定长度自变量 了解static方法 一.Java封装概念 在面向对象程式设计方法中,封装(英语:Encapsulation ...

  10. Java 学习笔记 ------第六章 继承与多态

    本章学习目标: 了解继承的目的 了解继承与多态的关系 知道如何重新定义方法 认识java.lang.object 简介垃圾回收机制 一.继承 继承是java面向对象编程技术的一块基石,因为它允许创建分 ...

随机推荐

  1. [SD心灵鸡汤]003.每月一则 - 2015.07

    乔布斯去世了,但他留给世人的财富却很多,值得每个人学习.他是个精力充沛魅力无限的家伙,同时也是一个很会鼓动人心的激励大师,甚至在他的平常对话中,经典的语句也常常脱口而出. 这里摘取了一些他的经典语录, ...

  2. [工具推荐]002.SoftOrbits Sketch Drawer使用教程

    SoftOrbits Sketch Drawer是一款简单易用的照片素描化软件,内置多种预设方案以及丰富的自定义细节. 只需要一次轻轻的鼠标点击,就可以帮助你迅速的将家人的照片转换为黑白或者彩色的素描 ...

  3. Sniffer截包工具的使用

    Sniffer软件的安装 sniffer需要在xp或者win2003环境下才能正常运行,如果没有这两个系统,可以安装虚拟机,在虚拟机上使用sniffer.如果没有这两个系统就会出现找不到网卡或者打不开 ...

  4. SD.Team团队人物形象

    AC   Mount   Zergling   Horse   Preacher   Alpha   注:无排名,仅按搞出来的时间先后排列.SD.Team犯罪团伙!!!!!!!! 本站文章为宝宝巴士 ...

  5. 04 . 前端之JQuery

    JQuery简介 # 1. jQuery是一个轻量级的.兼容多浏览器的JavaScript库.# 2. jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方便地 ...

  6. LayUI laydate日期选择器自定义 快捷选中今天、昨天 、本周、本月等等

    1. 引入laydata插件 下载 https://blog-static.cnblogs.com/files/zhangning187/laydate.js laydate.js 替换laydate ...

  7. golang内置类型和内置函数

    golang内置类型和内置函数是不需要引入包直接可用的 golang内置类型: 数值类型 string int,unint float32,float64 bool array 有长度的 comple ...

  8. linux 最基本的命令

    1.说一些你比较常用linux指令 1.1.ls/ll.cd.mkdir.rm-rf.cp.mv.ps -ef | grep xxx.kill.free-m.tar -xvf file.tar.(说那 ...

  9. Multiple annotations found at this line:- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path

    解决办法: 右键所在项目 build path configure build path java build path Add Library server Run time (Apache Tom ...

  10. PELT(Per-Entity Load Tracking)

    引言 对于Linux内核而言,做一款好的进程调度器是一项非常具有挑战性的任务,主要原因是在进行CPU资源分配的时候必须满足如下的需求: 1.它必须是公平的 2.快速响应 3.系统的throughput ...