java异常——捕获异常+再次抛出异常与异常链

【0】README

0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java异常——捕获异常+再次抛出异常与异常链 的相关知识;


【1】捕获异常相关

1.1)如果某个异常发生的时候没有再任何地方进行捕获, 那程序就会运行终止: 并在控制台上打印出异常信息 , 其中包括异常的类型堆栈的内容;

1.2)要想捕获一个异常, 必须设置 try/catch 语句块:

  • 1.2.1)如果在try语句块中抛出了一个在 catch子句中声明的异常类, 那么

    • case1)程序将跳过try 语句块的其余代码;
    • case2)程序将执行 catch 子句中 的处理器代码;
  • 1.2.2)如果在try语句块中没有抛出任何异常, 那么程序将跳过 catch子句;
  • 1.2.3)如果方法中的任何代码抛出了一个在 catch 子句中没有声明的异常类型, 那么这个方法就会立刻退出;

1.3)看个荔枝: (看一个读取文本的程序代码以演示捕获异常的处理过程)

public void read(String filename)
{
    try
    {
        InputStream in = new FileInputStream(filename);  // 创建输入流
        int b;
        while((b=in.read()) != -1)
            process input
    }
    catch(IOException exception)
    {
        exception.printStackTrace(); // 打印栈轨迹;
    }
}

对上述代码的分析(Analysis):

  • A1)需要注意的是, try 语句中的大多数代码都很容易理解, 读取并处理文本行, 直到遇到文件结束符为止;(read 方法可能抛出一个IOException异常)
  • A2)在这种情况下, 将跳出整个while循环, 进入 catch子句, 并生成一个 栈轨迹;

1.4)对于一个普通 的程序来说, 处理以上的对异常处理的方法外,还有其他方法吗?

  • 1.4.1)通常, 最好的选择是: 什么也不做, 而是将异常传递给调用者;如果read方法出现了错误, 那就让read方法的调用者去处理。
  • 1.4.2)如果采用这种方式, 就必须声明这个方法可能抛出一个 IOException(将异常传递给调用者);
public void read(String filename) throws IOException
{
        InputStream in = new FileInputStream(filename);  // 创建输入流
        int b;
        while((b=in.read()) != -1)
            process input
}

Attention)编译器严格地执行 throws 说明符。 如果调用了一个抛出已检查异常的方法, 就必须对它进行处理, 或者将它继续进行传递;

1.5)对于以上两种处理异常的方法, 哪种 方法更好呢?(method1:自己处理(在可能发生异常的函数中添加try/catch 语句块);method2:将异常传递(throw)给调用者,调用者处理)

  • 1.5.1)通常, 应该捕获那些知道如何处理的异常, 而将那些不知道怎么处理的异常继续进行传递;如果想传递一个异常, 就必须在方法的首部添加一个throws 说明符, 以便告知调用者这个方法可能会抛出异常;
  • 1.5.2)阅读API后, 以便知道这个方法可能会抛出哪种异常, 然后再决定是自己处理, 还是添加到 throws 列表中;

Attention)以上规则有个例外: 前面提到, 如果编写一个 覆盖超类的方法, 而这个方法又没有抛出异常, 那么这个方法就必须捕获方法代码中出现的每一个已检查异常。不允许在子类的 throws 说明符中出现超过超类方法所列出的异常类范围;(也就是说父类方法没有抛出异常,你子类方法也不准抛出异常,只能自己添加 try/catch 语句块自己处理)


【2】捕获多个异常

2.1)在一个try 语句块中可以捕获多个异常, 并对不同类型的异常做出不同的处理。可以按照下列方式为每个异常类型使用一个单独的 catch 子句;

try
{}
catch(FileNotFoundException e)
{}
catch(UnknownHostException e)
{}
catch(IOException e)
{}

2.2)要想获得异常对象 的更多信息: 可以试着使用 e.getMessage() 得到详细的错误信息, 或者使用 e.getClass().getName(); 得到异常对象 的实际类型;

2.3)合并catch 子句: 在 java SE7中, 同一个 catch 子句中可以捕获多个异常类型。 例如, 假设对应缺少文件和 未知主机异常的动作是一样的, 就可以合并catch 子句:

try
{}
catch(FileNotFoundException | UnknownHostException e)
{}
catch(IOException e)
{}

Attention)

  • A1)只有当捕获的异常类型彼此间不存在子类关系时 才需要这个特性;
  • A2)捕获多个异常时, 异常变量隐含为 final变量。例如, 不能在以下子句体中为 e 赋不同的 值;

    catch(FileNotFoundException || UnknownHostException e) {}

  • A3)捕获多个异常不仅会让你的代码看起来简单, 还会更高效。生成的字节码只包含一个对应公共catch 子句的代码块;

【3】再次抛出异常与异常链

3.1)在catch子句中可以抛出一个异常, 这样做的目的是 改变异常类型;

  • 3.1.1)看个荔枝:
try
{}
catch(SQLException e)
{
    throw new ServletException("data error : " + e.getMessage());
}

对以上代码的分析(Analysis):

  • A1)这里, ServletException 用带有异常信息文本的构造器来构造;
  • A2)不过, 可以有一种更好的方法, 并且将原始异常设置为新异常的原因:
try
{}
catch(SQLException e)
{
    Throwable se = new ServletException("database error");
    se.initCause(e);
    throw se;
}
  • A3)当捕获到这个异常时, 就可以使用下面的语句重新得到 原始异常:
Throwable e = se.getCause();

Attention)强烈建议使用这种包装技术, 这样可以让用户抛出子系统中的高级异常, 而不会丢失原始异常的小细节; (推荐使用 strongly recommended)

Hint)

  • H1)如果在一个方法中发生了一个已检查异常,而不允许抛出它, 那么包装技术就十分有用。 我们还可以捕获这个已检查异常, 并将它包装成一个 运行时异常;
  • H2)有时候, 你可能只想记录一个异常,再将它重新抛出, 而不做任何改变:
try
{
    access the database
}
catch(Exception e)
{
    logger.log(level, message, e);
    throw e;
}
  • H3)在Java SE7 之前, 将上述代码放入下述方法中, 会出现一个问题;
public void updateRecord() throws SQLException
  • 因为, java 编译器查看catch 块中的 throw 语句, 然后查看e的类型, 会指出这个方法可以抛出任何Exception而不仅仅是 SQLException;
  • H4)java se 7之后(编译器检测语法合法): 编译器会跟踪到 e 来自于try块中, 假设这个 try 块中仅有 的已检查异常 是 SQLException实例, 另外,假设e在catch块中未改变, 将外围方法声明为 throws SQLException 就是合法的;

原文地址:https://www.cnblogs.com/jpfss/p/9454592.html

时间: 2024-08-02 12:26:16

java异常——捕获异常+再次抛出异常与异常链的相关文章

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

第11章 异常,断言,日志,调试 处理错误 捕获异常 使用异常机制的技巧 使用断言 日志 測试技巧 GUI程序排错技巧 使用调试器 11.1 处理错误 11.1.1异常分类 都继承自Throwable类 分成Error和Exception Error类 描写叙述了Java运行时系统的内部错误和资源耗尽错误. 应用程序不应该抛出此种类型的错误.假设出现了这样的内部错误.除了通告给用户,并尽力使程序安全地终止外,再也无能为力 Exception层次结构:最需关注的 RuntimeException

java学习中,异常和错误的简介、捕获异常、抛出异常、自定义异常(java 学习中的小记录)

java学习中,异常和错误的简介.捕获异常.抛出异常.自定义异常(java 学习中的小记录)作者:王可利(Star·星星) 异常:(API 的 java.lang 有一个异常,有很多很多) 在Java程序中也会程序出现不正常的情况,这个就叫异常.     Java是面向对象的语言,任何事物都可以用类来描述,同样的异常也是一种事物.Java中提供了很多的异常类.     多个异常堆积起来,就是一个异常体系.   Throwable:是异常类的父类,超类.Exception 异常.error错误.

第十二章 重新抛出异常与异常链

重新抛出异常: 如果你想把刚捕获的异常扔给上一级处理,尤其是在使用Exception捕获所有异常的时候,既然已经得到了对当前异常对象的引用,可以直接把它重新抛出.重新抛出会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略,但finally块不会.此外,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息. 1 package 异常.Finally; 2 3 import java.io.IOException; 4 5

Core Java 经典笔试题总结(异常类问题)

所有代码均在本地编译运行测试,环境为 Windows7 32位机器 + eclipse Mars.2 Release (4.5.2) 2016-10-17 整理 下面的代码输出结果是多少?为什么?并由此总结几个编程规范. 1 class smallT { 2 public static void main(String args[]) { 3 smallT t = new smallT(); 4 int b = t.get(); 5 System.out.println(b); 6 } 7 8

Java中抛出的各种异常

目录(?)[-] 引子 JAVA异常 处理异常机制 捕获异常trycatch 和 finally try-catch语句 trycatch-finally语句 try-catch-finally 规则异常处理语句的语法规则 trycatchfinally语句块的执行顺序 抛出异常 throws抛出异常 使用throw抛出异常 Throwable类中的常用方法 Java常见异常 runtimeException子类 IOException 其他 自定义异常 1. 引子 try…catch…fina

黑马程序员---java基础-----多态、内部类、异常、包

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 第一讲     多态 多态可以理解为事物存在的多种体现形态. 例:动物中猫,狗.猫这个对象对应的类型是猫类型,如:猫 x = new猫();同时猫也是动物中的一种,也可以把猫称为动物.动物  y = new猫();那么动物就是猫和狗具体事

Java必知必会:异常机制详解

一.Java异常概述 在Java中,所有的事件都能由类描述,Java中的异常就是由java.lang包下的异常类描述的. 1.Throwable(可抛出):异常类的最终父类,它有两个子类,Error与Exception. Throwable中常用方法有: getCause():返回抛出异常的原因.如果 cause 不存在或未知,则返回 null. getMeage():返回异常的消息信息. printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值.

Java基础---多态、内部类、异常、包

第一讲     多态 多态可以理解为事物存在的多种体现形态. 例:动物中猫,狗.猫这个对象对应的类型是猫类型,如:猫 x = new猫(); 同时猫也是动物中的一种,也可以把猫称为动物.动物  y = new猫(); 那么动物就是猫和狗具体事物中抽取出来的父类型.父类型引用指向了子类对象. 一.多态的体现        1.父类的引用指向了自己子类的对象. 2.父类的引用也可以接收自己的子类对象. 如:   Animal a = new Cat(); 其中就将父类型的 a 引用指向了子类的对象.

java基础第十篇之异常

1.1接口概念 类:具有相同属性和功能的事物集合 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”. 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成.这样将功能的定义与实现分离,优化了程序设计. 请记住:一切事物均有功能,即一切事物均有接口. 与定义类的class不同,接口定义时需要使用interface关键字. 定义接口所在的仍为.java文件,虽然声明时使用的为interface关键字的编译后仍然会产生.class文件.这