`
jxwnhj0717
  • 浏览: 6948 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java语言精粹之三:异常系统

阅读更多
使用Java的异常通常都有以下困惑:
1、 不知道怎么处理异常
2、 直接忽略异常,统统throw
3、 简单的catch住,然后e.printStaceTree()
4、 处理了异常,但使得代码凌乱,主线代码不清晰

在正确的使用异常前,先了解下Java异常。异常的基类为Throwable。 Throwable和Return有些许类似,Return的作用是从一个方法返回到调用方,然后继续顺序执行代码,Throwable的作用是以抛出异常的形式来返回调用方,但不是顺序执行,而是从异常处理块处继续执行。比如:
public void test() {
  try {
    work();
    log("done!");
  } catch (Throwable e) {
    log("error prompt", e);
    rework();
  }
}

上述代码会先执行work(),如果顺利执行则会打印 done!,如果work()内部出现异常,则会跳到异常处理块,记录异常信息,然后调用rework(),而不会打印 done!,这样代码就从主流程转向了异常处理,或者说错误处理的流程。

在那些没有异常的语言中,比如C,常常见到这样的情况,返回一个特定的值(0/-1)来表示错误,作为调用方需要搞清楚方法返回什么表示出错了。为了处理错误,我们还要在调用方法后马上检查返回值是不是0/-1,是怎么办,不是又怎么办,这样错误的处理流程和正确的处理流程又紧密的耦合在了一起。这样的代码无论是维护,还是扩展都非常困难的,所以也有人索性忽略错误处理。只关注或主要关注正确的流程。在Java的开发者中,也存在着那么一批人,从来不理会异常。如果你也是那么做的,就请赶紧停下这罪恶的行径,认真地体会异常系统的思想和优势。

Java异常机制的思想是:错误处理应该从非错误的主线代码流程中分离出去,且指示错误的方式应该是显式的,而不是依靠返回值的使用习惯。方法的返回值应该是它正常、无错地完成时产生的结果。如果有错误发生,那些代码应该放在别处,并关联到一个能指出是什么错误的对象上。

文章的开始有提到Java异常和Return类似,都能从方法中返回,但什么时候应该使用Return返回,什么时候应该用异常来返回(抛出)呢?异常返回的是出乎预料、让人很惊讶的结果,而Return返回的正常的结果。举个例子,我们出去吃饭,正常的情况下饭菜可口,三下五除二就吃完了,或者菜难吃点,磨磨唧唧地吃完。但是如果正当你吃的不亦乐乎的时候,突然发现白色的米饭粒里夹着一粒黑乎乎的老鼠屎,这就是异常情况。
当你看到这粒老鼠屎后,你可以自由选择处理老鼠屎(异常)的方式:
1、把老鼠屎丢一边继续吃,我们称这样的系统容灾性很强
2、恶心吃不下去,结帐走人,这叫因异常抛出而放弃业务的继续处理
3、找相关人员处理,这叫业务流程的异常处理方式
4、把桌子掀了……这是错误发生时的蝴蝶效应,一个业务的异常导致其他业务不能正常使用
5、其他情况
还有一种方式,就是不管有没有老鼠屎都照吃,这就是不处理异常的方式。

Java的异常经常被人滥用,常见的滥用方式有以下几种:
1、 对每个会抛出异常的代码分别catch住。
public void test() {
  try {
    execSql1();
  } catch (SQLException e) {
    log("error prompt", e);
  }
  try {
    execSql2();
  } catch (SQLException e) {
    log("error prompt", e);
  }
  //to other things…
}

除非你不希望execSql1()的执行影响到execSql2()的执行(比如关闭流的时候),否则不应该这么做,这样不是很好的分离主线代码/错误代码的方式,改进:
public void test() {
  try {
    execSql1();
    execSql2();
  } catch (SQLException e) {
    log("error prompt", e);
  }
  //to other things…
}

2、 先catch了异常类A,然后再catch异常类A的子类
public void test() {
  try {
    execSql();
  } catch (Exception e) {
    // 执行一些动作
  } catch (SQLException e) {
    // 执行其他动作
  }
}

SQLEXCEPTION是EXCEPTION的子类,这里由于先catch住了EXCETPION,也就包括了SQLEXCEPTION,第二个catch子句永远都不会执行了。千万不要这么做,这样的错误很难查出。改进:
public void test() {
  try {
    execSql();
  } catch (SQLException e) {
    // 执行一些动作
  } catch (Exception e) {
    // 执行其他动作
  }
}

3、 简单的打印异常或忽略异常
public void test() {
  try {
    execSql();
  } catch (Exception e) {
    // 什么也不做
  } 
  try {
    doOtherThing();
  } catch (Exception e) {
    e.printStackTrace()
  } 
}

如果什么都不打印是最邪恶的处理方式,因为在运行环境中没有提示信息,你可能根本不知道错误在哪里。仅仅打印到控制台也不可取,因为你收到错误的时间可能距离错误发生的时间已经过去了好几个小时,而控制台的信息很可能被别的信息覆盖(window平台),也可能因为太大而无法查阅(linux平台)。改进:应该采用日志形式输出,比如log4j等等。

Exception&RuntimeException
Throwable有两个子类,Exception和RuntimeException。如果你抛出了Exception,那么意味着你要在方法签名里申明异常,并且在调用该方法时必须处理可能抛出的异常,否则就不能通过编译。这看起来好像很麻烦,但是Java提供了另一种异常RuntimeException,你不需要申明,也可以不处理,这看起来好像又很方便,于是部分程序员将所有抛出的异常都定义成RuntimeException子类,把不是RuntimeException的异常包装成RuntimeException,并认为自己巧妙的运用了异常。如果你也是这么做的,那就需要了解一下RuntimeException设计的初衷,明白什么时候才要使用它。

最初设计异常系统的时候,人们担心程序在运行期间会因为硬件问题、JVM的bug、安全等而产生异常,这种异常通常是应用程序无法处理的。为了将这类无法处理的问题和一般性问题区分开,于是Java提供了RuntimeException,这中异常无需声明,也不用处理,以保持程序的简洁。但是我们不能因为RuntimeException这种便利性而盲目的使用它,大部分异常还是需要声明,也需要处理的,是因为这是你应该做的,只有这样做才能保证程序的健壮性。

作者思路:
1、 异常的使用方法,和return的比较
2、 描述异常的设计理念
3、 举例描述异常如何工作
4、 列举异常不规范的使用方式
5、 RuntimeException的由来、使用探讨

后话:
我感觉作者是明显反对RuntimeException,提倡Exception的使用,但是我觉得还是Java异常系统设计的不够得体,当然也可能是我太菜没领会到精髓。我认为,一般抛出的异常应用程序一般都无法处理,只能记录错误,并通过修正源代码来解决。但是Java异常系统可以有效地分离主线代码和异常处理代码,提供足够的调试信息,我觉得这才是它实用的地方。
分享到:
评论

相关推荐

    java语言精粹

    ### Java语言精粹之异常处理 #### 引言 在《Java语言精粹》这本书中,作者Jim深入探讨了Java语言及其环境中的诸多亮点。其中一个关键主题是异常处理。异常处理是Java编程的一个核心概念,它对于确保程序的健壮性...

    Java Web项目开发案例精粹02-投票系统

    【Java Web项目开发案例精粹02-投票系统】是一个非常适合初学者的实践项目,它主要涉及了Java Web开发中的核心技术和基本业务流程。在这个项目中,你可以学习到如何使用Java语言、Web框架以及数据库技术来构建一个...

    疯狂java讲义精粹(第2版)

    这本书的核心目标是帮助读者深入理解Java语言的本质,提升编程技能,并掌握实际开发中的关键技术。以下是该书涵盖的一些关键知识点: 1. **Java基础**:讲解了Java的基本语法,包括数据类型、变量、运算符、流程...

    疯狂Java讲义精粹随书光盘

    通过《疯狂Java讲义精粹》的学习,读者不仅可以全面了解Java语言,还能提升编程技巧和解决问题的能力。对于初学者来说,这是一本很好的入门书籍;对于有一定经验的开发者,它也能提供有价值的参考和深化理解。

    Java案例精粹150例 高清完整版

    该压缩包包含了一份PDF文档,名为“Java案例精粹150例.pdf”,很可能包含了150个精心挑选的Java编程实例,涵盖了Java语言的核心特性、标准库的使用、面向对象编程原则以及常见的设计模式等众多知识点。以下是可能...

    Java精粹:从基础到高级 - 一个全面的学习指南

    Java基本功​​:Java入门:涵盖了Java语言的特点、JVM、JDK、JRE的详细解释,Oracle JDK与OpenJDK的对比,Java和C++的区别,以及Java程序的主类定义等。基本数据类型:详细介绍了Java中的基本数据类型及其包装类,...

    Java案例精粹150例(源代码)_java_

    Java作为世界上最流行的编程语言之一,广泛应用于各种领域,如企业级应用、移动开发、大数据处理等。本资源“Java案例精粹150例(源代码)”提供了丰富的实践示例,帮助开发者深入理解和掌握Java的核心概念及技术。...

    JAVA编程精粹.rar

    《JAVA编程精粹》是Java开发领域的一部经典著作,旨在深入探讨Java语言的核心概念、最佳实践以及高级特性。此压缩包包含的主要内容是“编程精粹”这一CHM格式的电子书,它涵盖了广泛的Java编程知识,对于初学者和...

    疯狂Java讲义精粹(第二版)

    本资源主要聚焦于Java语言的实践应用,特别是通过代码示例来阐述关键的设计模式和项目实践。 在压缩包中,"Java设计模式(疯狂Java联盟版).chm"是一个帮助文件,它详细介绍了Java设计模式。设计模式是软件开发中的...

    Java Web项目开发案例精粹03-在线考试系统

    1. **Java Web基础**:项目基于Java Web技术栈,这意味着它使用Java语言编写服务器端代码。开发者需要了解Servlet、JSP(JavaServer Pages)以及JSTL(JavaServer Pages Standard Tag Library)等基础知识,这些是...

    java案例精粹150例

    除了基础知识点,《Java案例精粹150例》还涵盖了Spring、Hibernate、MyBatis等流行框架的使用,以及如何集成第三方库,如Apache Commons、Guava等。这些案例不仅拓宽了读者的技术视野,还为解决特定领域的复杂问题...

    Java Web项目开发案例精粹15-个人理财管理系统

    1. **Java基础知识**:作为Java Web项目的基础,我们需要熟悉Java编程语言的基本语法、面向对象的概念以及异常处理机制。对于类、接口、继承和多态的理解是必不可少的。 2. **Servlet与JSP**:Servlet是Java Web...

    Java案例精粹150例+源代码

    源代码的分析和调试也是提高编程能力的重要环节,通过查看和运行代码,可以加深对Java语言特性的理解。因此,"Java案例精粹150例+源代码"是一个极好的学习资源,无论你是初学者还是有经验的开发者,都能从中受益匪浅...

    Java Web项目开发案例精粹ch01

    在这个章节中,开发者将深入学习如何运用Java语言,结合Web框架(如Spring、Struts或Hibernate等)来设计和实现高效、稳定的企业级应用。同时,系统采用MySQL作为数据库存储解决方案,这使得数据处理更加经济、快速...

    Java Web项目开发案例精粹18-航空订票系统

    《Java Web项目开发案例精粹18-航空订票系统》是一个针对初学者设计的实践教程,旨在帮助新手深入理解Java Web开发技术在实际项目中的应用。本项目以航空订票系统为背景,涵盖了多种核心技术和关键概念,下面将详细...

    Java案例精粹150例 张怀庆编 2005年.pdf

    根据提供的文件信息,我们可以推断出这是一本关于Java编程案例的书籍——《Java案例精粹150例》,作者是张怀庆,出版时间为2005年。虽然部分内容似乎与该书的主题不符(提到了MATLAB/Simulink/C++等其他编程语言以及...

Global site tag (gtag.js) - Google Analytics