异常描述

1.简介

    为了全面了解“异常”的概念,先来分析一个实例。假定要编写一个Java程序,该程序读取用户输入的一行文本,并在终端显示该文本。这里是一个演示Java语言I/O功能的简答回显(echo)程序。如果认为代码一定能正常运行,则可以编写一下程序。

import java.io.*;
public class EchoDemo{
public static void main(String[] args){
System.out.println("Enter text to echo");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader inputReader = new BufferedReader(isr);
String inputLine = inputReader.readLine();
System.out.println("READ:\t"+inputLine);
}
}

分析这段代码,在EchoDemo类中,第3行声明了一个main方法;第4行提示用户输入文本;在第5、6行设置BufferReader对象连接到InputStreamReader,而InputStreamReader又连接到标准输入流System.in;第7行读入一行文本;第8行用标准输出流System.out显示出该文本。

    实际上EchoDemo类是完全有可能出现问题。要调用readLine方法的时候要正确读取输入,下面几种假设都必须成立:

  • 1.假定键盘有效,键盘能与计算机正常通信;
  • 2.假定键盘数据可从操作系统传输到Java虚拟机,又从Java虚拟机传输给inputReader。

 JDK执行结果

    readLine方法有事会产生IOException。编译器要求“捕获”或“声明”IOException。

  • “捕获(catch)”指当readLine方法产生错误时截获该错误,并处理或记录问题
  • “声明(declare)”指错误可能引发IOException,并通知调用该方法的任何代码:可能产生异常。

捕获异常

import java.io.*;
public class EchoDemo{
public static void main(String[] args){
System.out.println("Enter text to echo");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader inputReader = new BufferedReader(isr);
try{
String inputLine = inputReader.readLine();
System.out.println("READ:\t"+inputLine);
}catch(IOException e){
System.out.println("Exception encountered:" + e);
} }
}

新添加的代码块包含关键字try和catch,表示如果要读取输入成功则正常运行,如果读取输入失败则捕获问题(由IOException对象表示),并采取相应的措施。

声明异常

import java.io.*;
public class EchoDemo{
public static void main(String[] args) throws IOException{
System.out.println("Enter text to echo");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader inputReader = new BufferedReader(isr);
String inputLine = inputReader.readLine();
System.out.println("READ:\t"+inputLine);
}
}

此代码中未采取措施来处理readLine方法的可能故障,但声明:main方法可能产生IOException,调用该方法的任何代码都必须做好处理问题的准备。

 JDK执行结果

2.异常概念

    Java等语言的大多数应用程序始终在使用消息。在GUI中,消息经常被用作发送事件信息(用户与应用程序交互的一些相关数据类型,如单击按钮,或在文本框中输入文本)的方式。

    从某种意义上说,异常就是这样的一种消息:她传递一些系统问题、故障及未按规定执行的动作的小官信息。异常包含信息,以将信息从应用程序的一部分发送到另一部分。

3.异常类的层次结构

    在Java中,所有异常有一个共同祖先Throwable(可抛出)。Throwable指定代码中可用异常传播机制通过Java应用程序传输的任何问题的共性。

    Throwable有两个重要的子类:Exception(异常)和Error(错误),二者都是Java异常处理的重要子类,各自都包含大量子类。

  • “异常”是应用程序中可能的可预测、可恢复问题。Java API文档记录给出的定义是:“合理应用程序可能需要捕获的情况。”一般地,大多数异常表示轻度到中度的问题。
  • “错误”表示运行应用程序中的比较严重问题。Java API文档记录给出的定义是:“是Throwable的一个子类,代表严重问题,合理应用程序不应该试图捕获。大多数此类错误属反常情况。”

    Java中的异常可以分为两种异常类型--受检异常(checked exception)和非受检异常(unchecked exception)。非受检异常指的是java.lang.RuntimeException和java.lang.Error类及其子类,其他所有的异常类都被称之为受检异常。两种类型的异常在作用上没有差别,唯一的差别是使用受检异常时的合法性要在编译时刻由编译器来检测,因此受检异常在使用的时候需要比非受检异常更多的代码来规避编译错误。

    一直以来,关于在程序中到底是该使用受检异常还是非受检异常,开发者之间一直存在着争议,毕竟两者各有优缺点。受检异常的特点在于它强制要求开发者在代码中进行显式的声明和捕获,否则就会产生编译错误。这种限制从好的方面来说,可以防止开发者意外地忽视某些出错的情况,因为编译器不允许出现未被处理的受检异常;从不好的方面来说,受检异常对程序中的设计提出了更高的要求。不恰当的使用受检异常,会使代码中充斥着大量没有实际作用、只是为了通过编译而添加的代码。而非受检异常的特点是,如果不捕获异常,不会产生编译错误,异常会在运行时刻才被抛出。非受检异常的好处是可以去掉一些不需要的异常处理代码,而不好之处是开发者可能忽略某些应该处理的异常。

    目前的主流意见是,最好优先使用非受检异常

4.异常的处理或声明

4.1 处理异常:try、catch和finally

如果想要捕获异常,则必须在代码中添加异常处理器块。这种Java结构可能包含3部分,都有Java关键字。
示例:

import java.io.*;
public class EchoDemo{
public static void main(String[] args){
System.out.println("Enter text to echo");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader inputReader = new BufferedReader(isr);
try{
String inputLine = inputReader.readLine();
System.out.println("READ:\t"+inputLine);
}catch(IOException e){
System.out.println("Exception encountered:" + e);
}finally{
System.out.println("My job here is done");
}
}
}

try块

    在将一个或者多个语句放入try时,则表示这些语句可能抛出异常。编译器知道可能要发生异常,于是用一个特殊结构评估块内所有语句。

catch块

    当问题出现时,一种选择是定义代码块来处理问题,catch块的目的便在于此。catch块是try块所产生异常的接受者。基本原理为:一旦生成异常,则try块的执行终止,JVM将查找相应的catch块。

finally块

    还可以定义这样一个代码块,无论试图运行try块代码的结果如何,该块一定运行。finally块的作用便在于此。在常见的所有环境中,finally块都将运行。无论try是否运行完,无论是否产生异常,也无论异常是否在catch块得到处理,finally都将运行。

4.2 try-catch-finally的规则

  • 必须在try之后添加catch或finally块。try块后可同时接catch和finally,且至少有一个块。
  • 必须遵守块的顺序:若代码同时使用catch和finally块,则必须将catch块放在try块之后。
  • try块与相应的catch或finally之间可能不存在语句。
  • catch块与特定异常的类型相关。
  • 一个try块可能有一个或者一个以上的catch块。如果是一个以上的catch块的话,将执行第一个匹配块。有一个经验法则:要按照从最具体到最一般的顺序组织处理块
  • 除下列情况,总将执行finally作为结束:

       a. JVM过早终止(调用System.exit(int))

       b. 在finlly块中抛出一个未处理的异常

       c. 计算机断电、失火,或遭遇病毒攻击
  • 可嵌套try-catch-finally结构。
  • 在try-catch-finally结构中可以重新抛出异常。

4.3 声明异常

若要声明,则必须将其添加到方法签名块的结束位置,即输入部分之后。
示例:

public void errorProneMethod(int input) throws java.io.IOException{
//Code for the method,including one or more method
//calls that may produce an IOException
}

这样,声明的异常将传给方法调用者,而且也通知了编译器:该方法的任何调用者必须遵守处理或声明规则。

4.4 声明异常的规则

  • 必须声明方法可能抛出的任何可检测异常(checked exception)。
  • 非检测异常(unchecked exception)不是必需的,可声明,也可不声明。
  • 调用方法必须遵守任何可检测异常的处理或声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

4.5 异常的API

    实际上,Java的Exception和Errors的所有行为都集中在Throwable类中。
其代码(节选)如下

public class Throwable implements Serializable {
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -3042686055658047285L; /**
* The throwable that caused this throwable to get thrown, or null if this
* throwable was not caused by another throwable, or if the causative
* throwable is unknown. If this field is equal to this throwable itself,
* it indicates that the cause of this throwable has not yet been
* initialized.
*
* @serial
* @since 1.4
*/
private Throwable cause = this; /**
* Specific details about the Throwable. For example, for
* {@code FileNotFoundException}, this contains the name of
* the file that could not be found.
*
* @serial
*/
private String detailMessage;
}

说明:

  • Throwable类定义实现Serializable接口,这意味着,Java的每个Exception类和Error类也实现Serializable接口。
  • Throwable存储3个属性:Message(消息)、Stack Trace(栈跟踪)和Cause(原因)。
名称 描述 读-写
Message String 描述性文本.详细介绍异常 读(只能在构造函数中设置)
Stack Trace StackTraceElement[] 引发异常的所有方法调用的记录 读-写
Cause Throwable 产生此异常的起因 读-写(只能设置一次)

Message进一步描述与异常相关的问题,可在两个构造函数中设置,可调用getMessage方法检索它

Stack Trace提供与异常相关的调用栈的记录--应用程序代码中特定异常导致代码停止执行的一系列位置。栈跟踪详细记录在抛出异常时执行停止的应用程序各点。

Cause是JDK1.4引入的新特性。这样,可以将另外一个Throwable对象指定为当前异常的“起因”。getCause和initCause方法提供了获取和设置此属性的方法。

5.异常声明是API的一部分

     主要是针对受检异常的。在一个公开方法的声明中使用throws关键词来声明其可能抛出的异常的时候,这些异常就成为这个公开方法的一部分,属于开放API。在维护这个公开API的时候,这些异常有可能会对API的演化造成阻碍,使得编写代码时不能不考虑向后兼容性的问题。

     如果公开方法声明了会抛出一个受检异常,那么这个API的使用者肯定已经使用了try-catch-finally来处理这个异常。如果在后面的版本更新中,发现该API抛出这个异常是不合适的,也不能直接把这个异常的声明删除。因为这样会造成之前的API使用者的代码无法通过编译。

     因此,对于API的设计者来说,谨慎考虑每个公开方法所申明的异常是很有必要的。因为一旦加了异常声明,在很长的一段时间内部都无法甩掉它。这也是为什么推荐使用非受检异常的一个重要原因,非受检异常不需要声明就可以直接抛出。但是对于一个方法抛出的非受检异常,也需要在文档中进行说明。

Java学习笔记--异常描述的更多相关文章

  1. Java学习笔记--异常机制

    简介 在实际的程序运行过程中,用户并不一定完全按照程序员的所写的逻辑去执行程序,例如写的某个模块,要求输入数字,而用户却在键盘上输入字符串:要求打开某个文件,但是文件不存在或者格式不对:或者程序运行时 ...

  2. java学习笔记 --- 异常

    异常 (1)程序出现的不正常的情况. (2)异常的体系   Throwable    |--Error  错误,严重问题,我们不处理.    ·    |--Exception 异常     |--R ...

  3. 0016 Java学习笔记-异常-如果try-catch-finally中都存在return语句会怎样?

    上午在搜索"System.runFinalization"的时候,搜到 http://www.cnblogs.com/Skyar/p/5962253.html ,其中有关于try- ...

  4. JAVA学习笔记—review基本知识[反射与异常]

    JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...

  5. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  6. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

  7. java学习笔记5--类的方法

    接着前面的学习: java学习笔记4--类与对象的基本概念(2) java学习笔记3--类与对象的基本概念(1) java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址 ...

  8. 20145230《java学习笔记》第九周学习总结

    20145230 <Java程序设计>第9周学习总结 教材学习内容 JDBC JDBC简介 JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作, ...

  9. java学习笔记之OOP(二)

    java学习笔记二.面向对象[OOP]Object Oriented Programming 一.三大特性: 1.封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用 ...

随机推荐

  1. UML总结(对九种图的认识和如何使用Rational Rose 画图)

    UML是一种建模语言,是系统建模的标准.我们之所以建模是因为大规模的系统设计时相当复杂的,当系统比较复杂时就会涉及到以下这几个问题: 开发人员如何与用户进行沟通来了解系统的需求? 开发人员之间如何沟通 ...

  2. js 检测浏览器

    首先还是IE浏览器的检测,一般我们在写代码的时候,出现的兼容性bug几乎都来自IE.从IE10以后,IE还算有点良心,支持了大部门的CSS3及H5的新特性.那么在IE10之前呢,就要才去别的手段来代替 ...

  3. iframe框架的应用

    同学接私活,我写几个页面. 后台系统,点击侧栏菜单后,右边div的要显示对应的内容.就是说,没选一下左边的菜单,右边的内容都要变化. 这次首先尝试了一下Oldfasional办法--iframe框架. ...

  4. mysql语句优化总结(一)

    Sql语句优化和索引 1.Innerjoin和左连接,右连接,子查询 A.     inner join内连接也叫等值连接是,left/rightjoin是外连接. SELECT A.id,A.nam ...

  5. 基于DotNet Core的RPC框架(一) DotBPE.RPC快速开始

    0x00 简介 DotBPE.RPC是一款基于dotnet core编写的RPC框架,而它的爸爸DotBPE,目标是实现一个开箱即用的微服务框架,但是它还差点意思,还仅仅在构思和尝试的阶段.但不管怎么 ...

  6. linux下安装一款笔记软件(为知笔记)

    今天突然想在ubuntu上安装一款跨平台(windows.linux.android)的笔记软件来做日常记录.文章记录以及网页收藏.原先并没有使用过类似的软件,只是见身边的很多人在使用印象笔记来做记录 ...

  7. JUnit之断言assert

    一.简介 JUnit4.4引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活: 使用全新的断言语法:assertThat,结合Ham ...

  8. MySQL锁(MyISAM和InnoDB)

    MySQL有三种级别的锁: 1. 页级别 BDB 2. 表级别 MyISAM 3. 行级别 InnoDB 就 总体而言MyISAM表的读和写是串行的.在一定条件下,MyISAM表也支持查询和插入操作的 ...

  9. (入门篇 NettyNIO开发指南)第五章-分隔符和定长解码器使用

    TCP    以流的方式进行数据传输上层的应用协议为了对消息进行区分,往往采用如下4种方式. (1)消息长度固定,累计读取到长度总和为定长LEN 的报文后,就认为读取到了一个完整的消息,将计数器置位, ...

  10. DOM4J介绍与代码示例(2)-XPath 详解

    XPath 详解,总结 XPath简介 XPath是W3C的一个标准.它最主要的目的是为了在XML1.0或XML1.1文档节点树中定位节点所设计.目前有XPath1.0和 XPath2.0两个版本.其 ...