《Java编程思想》阅读笔记6

摘要:
只有当对象是Throwable的实例时,才能通过Java虚拟机或Java throw语句将其抛出。

“Java的基本理念是:结构不佳的代码不能运行。”,从我原来使用Java的异常机制的感觉是不太喜欢的,因为他将整个异常的调用轨迹都放出来了,给人一种恐怖的感觉,现在慢慢体会着这里面的种种好处,感受着他们的设计思路。
1.开发异常的初衷
    在Java中,异常机制的使用的初衷是为了方便程序员处理可能的错误,其中一个重要原则是“只有在你知道如何处理的情况下才捕获异常”,同时也是将错误处理代码与正常运行逻辑的代码分开,增强可阅读与可维护性。如果常使用c语言的话,常常函数的调用是通过返回值来进行可能存在错误的判断,一旦情况复杂,直接干扰了正常运行逻辑的理解,看到的全是对可能问题的处理,因此,往往很少充分的去处理(这样确实简单,可以通过调试跟踪来解决,这个可能就是对问题的处理方式不同吧)。书中阐述了些“被检查的异常”和强静态类型检查对开发健壮程序的看法,强调异常报告和类型检查的重要性,但是也不限制死;自己在C语言中深感其灵活性(也是经常被弄得混乱无助),但在Java中还没有特别切身的感受,不好多说,留下来。
2.异常的抛出与捕获
 (1)异常的产生
    java.lang.Throwable是 Java 语言中所有错误或异常的基类。其直接子类为Error和Exception,Error用来表示系统的错误,一般应用程序不需要关心;Exception需要应用程序关心,是类库、用户方法及运行时可抛出的基本类型。只有当对象是Throwable(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。因此通常情况下,可以通过catch Exception来捕获想要的(关心的)所有异常,如果没有处理好同时也带来“吞食”异常的问题。
 (2)抛出与捕获(异常栈轨迹)
    可以通过继承Exception或者更为细的异常类型来创建自己所需要的异常,然后使用throw来抛出异常,遵循Java的对象使用,异常对象也是通过new在堆上创建,而且可以通过无参数的和带字符串为参数的构造器来构造异常对象,例如中的throw new NullPointerException("t = null");或者还能够通过cause来构造异常链。
    异常的捕获是将可能产生异常的语句放在try块中,然后在catch中处理异常;要说的是,可以通过printStackTrace()方法显示异常的调用栈轨迹,可以在捕获处来显示异常的调用轨迹,但是这里也涉及到如果未处理好异常,异常重新抛出后,栈轨迹的变化问题:如果想保留原来的调用栈轨迹,就直接抛出异常;而如果想更新这个信息,可以调用fillInStackTrace()方法。
    异常链,保存的所有异常的信息。Throwable的子类(Error、Exception、RuntimeException)在构造器中可以接受一个cause对象作为参数,这个cause可以作为新异常产生的前因,从而记录所有异常信息。
 (3)finally
    使用finally清理,无论try块中的异常是否抛出,它们都能得到执行,即使finally所连接的try方法中有return语句,也会保证finally的执行;虽然不能用作清理内存析构函数之类,但是可以在打开的文件或网络连接等地方使用。
3.异常的限制
    当覆盖方法时,只能抛出在基类方法的异常说明里列出的异常,从而使得基类使用的代码(方法)能够用到其子类上;当然,这个限制对构造器是不起作用的,但是子类的构造器的异常说明必须包含基类的异常说明,而且子类的构造器是不能捕获基类构造器抛出的异常。
最后一个异常的使用例子:通过printStackTrace()来进行异常栈轨迹的查看,而通过getCause()获取产生此异常发生的直接原因(异常),因而得到整个异常链。

package com.test.myjava;
/*
* @author w7849516230
*/

class FirstException extends Exception{
/*
* 利用默认的构造器
* Exception(String message, Throwable cause) 构造带指定详细消息和原因的新异常
* 下同
*/
FirstException(String str,Exception e){
super(str,e);
}
}
class SecondException extends Exception{

public SecondException(String str, Exception e) {
super(str,e);
}
}
class ThirdException extends Exception{

public ThirdException(String str) {
super(str);
}
}

public class ExceptionTest {
public void firstMethod() throws FirstException{
try {
secondMethod();
} catch (SecondException e) {
throw new FirstException("FirstException Test",e);
}
}
public void secondMethod() throws SecondException{
try {
thirdMethod();
} catch (ThirdException e) {
throw new SecondException("SecondException Test",e);
}
}
public void thirdMethod() throws ThirdException{
throw new ThirdException("ThirdException Test");
}


public static void main(String[] args){
ExceptionTest et = new ExceptionTest() ;
//打印异常栈
try {
et.firstMethod();
} catch (FirstException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

try {
et.firstMethod();
} catch (Exception e) {
try {
throw e.getCause();//捕获特定的异常进行处理
}catch(FirstException ef){
System.out.println("Catch FirstException!");
}catch(SecondException es){
System.out.println("Catch SecondException!");
try {
throw es.getCause();
}catch(ThirdException eth){
System.out.println("In SecondException Catch ThirdException!");
}catch (Throwable e1) {
// TODO Auto-generated catch block
System.out.println("Catch Exception in SecondException");
e1.printStackTrace();
}
}catch(ThirdException eth){
System.out.println("Catch ThirdException");
}
catch (Throwable e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
输出:

com.test.myjava.FirstException: FirstException Test
at com.test.myjava.ExceptionTest.firstMethod(ExceptionTest.java:34)
at com.test.myjava.ExceptionTest.main(ExceptionTest.java:53)
Caused by: com.test.myjava.SecondException: SecondException Test
at com.test.myjava.ExceptionTest.secondMethod(ExceptionTest.java:41)
at com.test.myjava.ExceptionTest.firstMethod(ExceptionTest.java:32)
... 1 more
Caused by: com.test.myjava.ThirdException: ThirdException Test
at com.test.myjava.ExceptionTest.thirdMethod(ExceptionTest.java:45)
at com.test.myjava.ExceptionTest.secondMethod(ExceptionTest.java:39)
... 2 more
Catch SecondException!
In SecondException Catch ThirdException!

免责声明:文章转载自《《Java编程思想》阅读笔记6》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Chart.js实现饼图fastcgi apache fcgi下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SpringBoot 构造器注入、Setter方法注入和Field注入对比

0. 引入 今天在看项目代码的时候发现在依赖注入的时候使用了构造器注入,之前使用过 Field 注入和 Setter 方法注入,对构造器注入不是很了解。经过查阅资料看到,Spring 推荐使用构造器注入的方式,下面介绍构造器注入到底有什么玄机。 1. 常见的三种注解注入方式对比 Field 注入 @Controller public class Hello...

SpringBoot + MyBatis(注解版),常用的SQL方法

一、新建项目及配置 1.1 新建一个SpringBoot项目,并在pom.xml下加入以下代码   <dependency>    <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starte...

[Java]重载,重写以及继承,多态的区别

转自:http://android.blog.51cto.com/268543/53181 什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承、多态、重载和重写。继承(inheritance)简单的说,继承就是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(下面会讲到,这种方式叫重写)的方...

Java 面向对象(六)类的成员 之 构造器(构造方法)

一、构造器   构造器又称构造方法,是为了创建对象和初始化对象所产生的。 二、构造器的特征   1、它具有与类相同的名称。   2、它不声明返回值类型。(与声明为 void 不同)   3、不能与 static、final、synchronized、abstract、native 修饰,不能有 return 返回值; 三、构造器的作用   作用:     ...

vue-创建组件的5种方法

Vue组件分为全局组件和局部组件以及Vue 构造器创建组件,统计为5种创建组件的方式 一、效果截图 创建的h1-h5五个组件 组件名称和结构 二、具体的写法如下: 1、全局-直接创建 Vue.component('first', { template: '<h1>第一种创建组件的方法</h1>' }) 2、全局-定义再...

Effective java -- 1

写博客我也不知道是不是一个好习惯,但是目前还不知道有什么其他更有效率的学习方法。现在的学习方法:看书,写博客。如果看明白一个东西,去写博客的话,这通常是一个浪费时间的行为,但是这个过程同样帮助自己二次记忆。并不知道写博客到底好不好。就先按照这个来吧。开始新的一本书,《Effective Java》 第一条:考虑用静态工厂方法代替构造器优点 静态工厂有名称...