Java编程中的异常处理是一个很常见的话题了,几乎任何一门介绍性的Java课程都会提到异常处理。不过,我认为很多人其实没有真正掌握正确处理异常情况的方法和策略,最多也就不过了解个大概,知道概念。我想对三种不同程度和质量的Java异常处理进行了讨论,所阐述的处理异常的方式按手法的高下分为:

好,不好和恶劣三种。

同时提供了一些解决这些问题的技巧。

首先解释一些java异常处理中必须搞清楚的定义和机制。Java语言规范将自Error类或RuntimeException类衍生出来的任何违例都称作“不可检查”(Unchecked)异常;其他所有异常则称作“可检查”(Checked)异常。

所谓可检查异常,是指我们应该自行处理的异常。至于处理的手段,要么加以控制(try catch),要么通告(throws)他们有可能产生。通常,应捕捉那些已知如何处理的异常,而通告那些不知如何处理的异常。

而对那些不可检查异常来说,他们要么在我们的控制之外(Error),要么是我们首先就不该允许的情况(RuntimeException)。

至于异常的指定,Java的规则非常简单:一个方法必须通告自己可能产生的所有可检查异常。编写自己的方法时,并不一定要通告出方法实际可能产生的每一个异常对象,要想理解什么时候必须要方法的throws丛句来通告异常,就必须知道对一个异常来说,他只有可能在下面四种情况下才会产生:

1.调用了可能产生异常的方法。比如BufferedReader类的readLine方法。该方法通告java.io.IOException异常

2。发现到一个错误,并用throw语句产生异常。

3.出现一个编程错误。比如a[-1] = 0。

4.Java产生内部错误。

如果出现头两种情况之一,必须告诉打算使用自己方法的人:假如使用这个方法,可能造成一个异常的产生(即在方法头上使用throws),一个简单的记忆方法:

只要含有throw,就要通告throws。如果一个方法必须同时处理多个异常,就必须在头内指出所有异常。

就像下例展示的那样,用逗号对他们进行分割:

1234567

    class Animation

    {

    public Image loadImage(Strint s)  throws EOFException,MalformedURLException

    {

    ……

    }

    }

然而,我们不需要通告内部java错误,也不应该通告自RuntimeException衍生出来的异常。

好的异常处理

好异常处理提供了处理程序错误的统一机制。事实上,Java语言通过向调用者提出异常警告的方式而显着地提升了软件开发中的异常处理能力。这种方式把Java语言中的“方法(method)”进行了扩展和增强,使之包括了自身的错误条件。下面就让我们看一个例子,这个例子说明了这种情况。

以下是FileInputStream构造器之一的原型:

public FileInputStream(String name) throws FileNotFoundException Java

的方法和构造器必须声明他们在被调用时可能“扔出”的异常,采用的关键字就是“throws”。这种在方法原型中出现的异常提示增加了编程的可靠性。

显而易见,这种方式是向方法的调用者提示了可能出现的异常条件,这样调用者就可以对这些异常作出适当的相应处理。以下代码示意我们是如何捕获并且处理FileNotFoundException 这一异常的:

 1234567891011

    try

    {

    FileInputStream fis = new FileInputStream(args[0]);

    // other code here …

    }

    catch (FileNotFoundException fnfe)

    {

    System.out.println("File: " + args[0] + " not found. Aborting.");

    System.exit(1);

    }

Java异常处理还有其他一些优秀的特性,这就是可检查异常、用户定义异常和在JDK 1.4中推出的新型Java记录API(Java Logging API)。java.lang.Exception的所有子类都属于可检查异常。可检查异常(checked exception)是扔出该异常的方法所必须提示的异常,这种异常必须被捕获或者向调用者提示。用户定义异常(User-defined exceptions)是定制的异常类,这种异常类扩展了java.lang.Exception类。优良的Java程序规定定制异常封装、报告和处理他们自己独有的情况。最新的Java记录API(logging API)则可以集中记录异常。 不好的Java异常处理

不好的一面包括两种情况:滥用不可检查异常(unchecked exceptions)和滥用catchall构造器等。这两种方式都使得问题变得复杂起来。

有一种类别的异常属于RuntimeException的子类,这种异常不会受到编译器的检查。比如,NullPointerException和 ArrayStoreException就是这种类型异常的实例。程序员可以对RuntimeException进行子类化以回避检查异常的限制,从而便于产生这些异常的方法为其调用者所使用。

专业的开发团队应当只允许在很少的情况下才可以这样做。

第二种异常处理的陋习是catchall构造器。所谓的“catchall 构造器”就是一种异常捕获代码模块,它可以处理所有扔给它的可能异常。

以下是catchall处理器的实例:

    123456789

    try

    {

    // code here with checked exceptions

    }

    catch (Throwable t)

    {

    t.printStackTrace();

    }

我得承认,我自己在编写一般程序的时候就曾经用过这种技术;但是,在编写关键程序的时候这种类型的构造器一定要避免使用,除非他们被授权可以和中央错误处理器联合使用才可以这样做。

除此之外,catchall构造器不过只是一种通过避免错误处理而加快编程进度的机制。

异常处理的一个不足之处是难以采用优良的错误处理策略。从低容内存状态恢复、写入错误和算法错误等异常情况都不是轻易能得到解决的。你可以尝试一下循环、垃圾收集和提醒用户等常用技术来应付以上的局面。

恶劣的处理方法

和许多Java特性及其API类似,Java的异常处理机制也有“霸王硬上弓”类的滑稽错误。比方说,为了扔出某个异常竟然毫不犹豫地用“new”关键词为其分配内存就是这样的例子。

我自己不知道有多少次就因为犯了这种错误而在严肃的编译器面前屡屡碰壁。在这种情况下,我们其实都是在伺候语言而不是让语言为我们所用。还有我们碰到的OutOfMemoryErrors就是异常处理的缺陷。这一处理过程是:

使用finally模块关闭文件,解析异常以得到出现问题的方法和代码行。在这一过程之内最大的缺陷是需要捕获OutOfMemoryError,而这一异常却并不是可检查异常!想想看,内存耗尽是相当常见的情况。任何与内存使用状态紧密相关的程序都应当捕获和处理这一错误。

使用异常时的一些建议

1.异常控制的设计宗旨并不是用来代替一些简单的测试。只有在异常情况下才使用异常!

2.不要过分细化异常。不要在每个语句上都加上异常处理,最好将整个任务都放在try块内。如果其中有一项操作失败,可以随即放弃任务。

3.不要“压制”异常。对于需要通告异常的方法,我们可以改用捕捉的方法来将异常强行关闭,如果真的出现异常,那个异常会被“静悄悄”的忽略。如果觉得产生的异常会非常重要,就必须多费些功夫,对其进行正确的控制。

4.不要介意异常的传递。如果调用的方法会产生异常,比如readLine方法,他们天生就能捕捉自己可能产生的异常,在这种情况下,一种更好地做法是将这些异常传递出去,而不是自己动手来捕捉它。

Java 异常处理的优劣的更多相关文章

  1. 札记:Java异常处理

    异常概述 程序在运行中总会面临一些"意外"情况,良好的代码需要对它们进行预防和处理.大致来说,这些意外情况分三类: 交互输入 用户以非预期的方式使用程序,比如非法输入,不正当的操作 ...

  2. java异常处理(父子异常的处理)

    我当初学java异常处理的时候,对于父子异常的处理,我记得几句话“子类方法只能抛出父类方法所抛出的异常或者是其子异常,子类构造器必须要抛出父类构造器的异常或者其父异常”.那个时候还不知道子类方法为什么 ...

  3. Java 异常处理

    异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用System.out ...

  4. 《转载》Java异常处理的10个最佳实践

    本文转载自 ImportNew - 挖坑的张师傅 异常处理在编写健壮的 Java 应用中扮演着非常重要的角色.异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可用.非法的输入.nul ...

  5. JAVA 异常处理机制

    主要讲述几点: 一.异常的简介 二.异常处理流程 三.运行时异常和非运行时异常 四.throws和throw关键字 一.异常简介 异常处理是在程序运行之中出现的情况,例如除数为零.异常类(Except ...

  6. Java异常处理和设计

    在程序设计中,进行异常处理是非常关键和重要的一部分.一个程序的异常处理框架的好坏直接影响到整个项目的代码质量以及后期维护成本和难度.试想一下,如果一个项目从头到尾没有考虑过异常处理,当程序出错从哪里寻 ...

  7. 深入理解java异常处理机制

       异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的 ...

  8. Java提高篇——Java 异常处理

    异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用Syst ...

  9. java异常处理的设计

    有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程序时,如何设计异常处理的代码,如何时抛异常,捕获到了怎么处理,而不是讲 ...

随机推荐

  1. 安装cfssl证书生成工具

    wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssljson_linux-am ...

  2. tmp_获取下一个回文数

    直接拿之前一次竞赛中写的code,稍微完善了点,后面有机会在优化 uint64_t GetNextPalindrome(uint64_t data) { //100以内的数字已经特殊考虑过,不存在差值 ...

  3. Powershell 备忘

    如何修改环境变量 [environment]::SetEnvironmentvariable(“path”,"xxx","user") [environment ...

  4. linux三剑客正则表达式

    ^:以...开头,^d,意思是以d开头.例如:ls  -F(-p) | grep " ^d " $:以...结尾,/$,意思是以/结尾.例如:ls -F(-p) | grep &q ...

  5. 《Spring源码深度解析》第三章 默认标签的解析

    上一章提到了,默认标签和自定义标签要分开解析.本章重点介绍默认标签的解析.在 DefaultBeanDefinitionDocumentReader 中: private void parseDefa ...

  6. python并发编程之线程剩余内容(线程队列,线程池)及协程

    1. 线程的其他方法 import threading import time from threading import Thread,current_thread def f1(n): time. ...

  7. ACM-ICPC 2018 徐州赛区网络预赛 I. Characters with Hash

    Mur loves hash algorithm, and he sometimes encrypt another one's name, and call him with that encryp ...

  8. poj 3614 奶牛美容问题 优先队列

    题意:每头奶牛需要涂抹防晒霜,其中有效的范围 min~max ,现在有L种防晒霜,每种防晒霜的指数为 f 瓶数为 l,问多少只奶牛可以涂上合适的防晒霜?思路: 优先队列+贪心 当奶牛的 min< ...

  9. Linux学习-磁盘配额 (Quota) 的应用与实作

    什么是 Quota 在 Linux 系统中,由于是多人多任务的环境,所以会有多人共同使用一个硬盘空间的情况发生, 如 果其中有少数几个使用者大量的占掉了硬盘空间的话,那势必压缩其他使用者的使用权力! ...

  10. MySQL-状态Waiting on empty queue引申

    MySQL 事件调度器示例演示 我们大家都知道MySQL 事件调度器是在 MySQL 5.1 中新生的一个较为特殊的功能,其可以作为定时任务调度器,来取代部分原先只能用操作系统任务调度器才能完成的定时 ...