Java异常处理、测试与调试

原创|其它|编辑:郝浩|2009-03-06 09:58:43.000|阅读 1244 次

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

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

1.3  异常类层次结构

在总体上介绍异常后,接下来将讨论Java异常类层次结构。图1-3显示Java的异常组织方式。

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

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

“异常”是应用程序中可能的可预测、可恢复问题。Java API文档记录给出的定义是:“合理应用程序可能需要捕获的情况。”一般地,大多数异常表示轻度到中度的问题。

异常一般是在特定环境下产生的,通常出现于代码的特定方法或操作中。在EchoInput类中,当试图调用readLine方法时,可能产生IOException异常。

1-3  Java异常类层次结构

“错误”表示运行应用程序中的较严重问题。Java API文档记录给出的定义是:“是Throwable的一个子类,代表严重问题,合理应用程序不应试图捕获它。大多数此类错误属反常情况。”

大多数错误与代码编写者执行的操作无关,而表示代码运行时JVM(Java虚拟机)出现的问题。例如,当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError

Exception类有一个重要子类RuntimeExceptionRuntimeException及其子类表示“JVM常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零,或数组越界,则将分别引发运行时异常(NullPointerExceptionArithmeticException)ArrayIndexOutOfBoundException

 

1.4  异常的处理或声明选项

前面的示例代码曾提到过,在处理潜在故障时,有两个选项。在调用可能引发异常的方法时,可以捕获异常,也可以声明该方法抛出异常。这就是常说的“处理(handle)或声明(declare)”规则。

怎样通知Java编译器要遵循代码中的处理或声明规则?回顾一下,java.io.BufferedReader类中readLine的方法签名指示该方法调用将抛出IOException

1.4.1  处理异常:trycatchfinally

若要捕获异常,则必须在代码中添加异常处理器块。这种Java结构可能包含3部分,都有Java关键字,下例演示try-catch-finally代码结构。

1  import java.io.*;

2  public class EchoInputTryCatchFinally{

3       public static void main(String [] args){

4            System.out.println("Enter text to echo");

5            InputStreamReader isr = new InputStreamReader(System.in);

6            BufferedReader inputReader = new BufferedReader(isr);

7            try{

8                 String inputLine = inputReader.readLine();

9                 System.out.println("READ: " + inputLine);

10            }

11            catch (IOException exc){

12                 System.out.println("Exception encountered: " + exc);

13            }

14            finally{

15                 System.out.println("My job here is done.");

16            }

17      }

18 }

1. try

在将一个或多个语句放入try时,则表示这些语句可能抛出异常。编译器知道可能要发生异常,于是用一个特殊结构评估块内所有语句。在包括了测试可能问题的代码,下一步该做什么?有哪些选择?

2. catch

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

在上例中,第11行的catch块使用IOException类型的参数。catch块对异常执行instanceof测试:若抛出的异常是IOException类或子类,则该代码块运行。在try-catch结构中,可能有多个catch块;此时,异常将交由第一个匹配的catch块处理。

3. finally

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

1.4.2  try-catch-finally的规则

    必须在try之后添加catchfinally块。try块后可同时接catchfinally块,且至少有一个块。

    必须遵守块顺序:若代码同时使用catchfinally块,则必须将catch块放在try块之后。

    try块与相应的catchfinally之间可能不存在语句。

    catch块与特定异常类的类型相关。

    一个try块可能有多个catch块。若如此,将执行第一个匹配块。有一个经验法则:要按从最具体到最一般的顺序组织处理块。

    除下列情况,总将执行finally作为结束:

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

b. finally块中抛出一个未处理的异常。

c. 计算机断电、失火,或遭遇病毒攻击。

    可嵌套try-catch-finally结构。

    try-catch-finally结构中,可重新抛出异常。

1.4.3  声明异常

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

1  public void errorProneMethod(int input) throws java.io.IOException{

2      // Code for the method, including one or more method

3      // calls that may produce an IOException

4  }

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

1.4.4  声明异常的规则

    必须声明方法可能抛出的任何可检测异常(checked exception)

    非检测异常(unchecked exception)不是必需的,可声明,也可不声明。

    调用方法必须遵守任何可检测异常的处理或声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类

 

1.5  可检测异常和非检测异常

Java的可检测异常和非检测异常泾渭分明。可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则。

非检测异常不遵循处理或声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已解决了这样一个异常。有两个主要类定义非检测异常:RuntimeExceptionError

为什么Error子类属于非检测异常?这是因为无法预知它们的产生时间。若Java应用程序内存不足,则随时可能出现OutOfMemoryError;起因一般不是应用程序中的特殊调用,而是JVM自身的问题。另外,Error类一般表示应用程序无法解决的严重问题,故将这些类视为非检测异常。

RuntimeException类也属于非检测异常,一个原因是普通JVM操作引发的运行时异常随时可能发生。与Error不同,此类异常一般由特定操作引发。但这些操作在Java应用程序中会频繁出现。例如,若每次使用对象时,都必须编写异常处理代码来检查null引用,则整个应用程序很快将变成一个庞大的try-catch块。因此,运行时异常不受编译器检查与处理或声明规则的限制。

RuntimeException类作为未检测异常还有一个原因:它们表示的问题不一定作为异常处理。可以在try-catch结构中处理NullPointerException,但若在使用引用前测试空值,则更简单,更经济。同样,可以在除法运算时检查0值,而不使用ArithmeticException

 

1.6  异常的API

实际上,JavaExceptionsErrors的所有行为都集中在Throwable类中。表1-1列出该类的API

1-1  java.lang.ThrowableAPI

public class Throwable implements Serializable

构造函数总结

Throwable()

Constructs a new throwable with null as its detail message.

Throwable(String message)

Constructs a new throwable with the specified detail message.

1.4 Throwable(String message, Throwable cause)

Constructs a new throwable with the specified detail message

and cause.

1.4 Throwable(Throwable cause)

Constructs a new throwable with the specified cause and a

detail message of (cause==null ? null : cause.toString())

(which typically contains the class and detail message of cause).

方法总结

Throwable fillInStackTrace()

Fills in the execution stack trace.

1.4 Throwable getCause()

Returns the cause of this throwable or null if the cause is

nonexistent or unknown.

1.1 String getLocalizedMessage()

(续表)  

Creates a localized description of this throwable.

String getMessage()

Returns the detail message string of this throwable.

1.4 StackTraceElement[] getStackTrace()

Provides programmatic access to the stack trace information

printed by printStackTrace().

1.4 Throwable initCause(Throwable cause)

Initializes the cause of this throwable to the specified value.

1.1 void printStackTrace()

Prints this throwable and its backtrace to the standard error

stream.

void printStackTrace(PrintStream s)

Prints this throwable and its backtrace to the specified print

stream.

void printStackTrace(PrintWriter s)

Prints this throwable and its backtrace to the specified print

writer.

1.4 void setStackTrace(StackTraceElement[] stackTrace)

Sets the stack trace elements that will be returned by

getStackTrace() and printed by printStackTrace() and related

methods.

String toString()

Returns a short description of this throwable.

 

注意,Throwable类定义实现Serializable接口,这意味着,Java的每个Exception类和Error类也都实现Serializable接口。

串行化意味着可使用Java流将异常发送到其他目标位置。目标位置可能是提供永久存储的文件,也可能是另一个JVM,从而在分布式系统通过网络连接发送异常。这个特性非常重要,在讨论分布式系统的异常和API时将用到它。

Throwable存储3个属性:Message(消息)Stack Trace(栈跟踪)Cause(原因)。表1-2总结了各个属性。

1-2  Throwable类的属性

   

   

-

Message

String

描述性文本,详细介绍异常

(只能在构造函数中设置)

Stack Trace

StackTraceElement [ ]

引发异常的所有方法调用的记录

-

Cause

Throwable

产生此异常的起因

-(只能设置一次)

 

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

Stack Trace 提供与异常相关的调用栈的记录——应用程序代码中特定异常导致代码停止执行的一系列位置。栈跟踪详细记录在抛出异常时执行停止的应用程序各点。栈跟踪的相关方法是getStackTracesetStackTrace,以及fillInStackTrace和所有printStackTrace方法。第3章将详细介绍栈跟踪。

Cause JDK 1.4引入的新特性。这样,可以将另一个Throwable对象指定为当前异常的“起因”。getCauseinitCause方法提供了获取和设置此属性的方法,此外还有两个构造函数允许设置异常的起因。第3章分析Cause的用法。

除了上述3个属性外,Throwable还包含toStringgetLocalizedMessage方法。toString方法覆盖Object类,返回异常名(对于非空消息字符串)getLocalizedMessage方法仅返回消息字符串的值。

 

1.7  小结

本章简要介绍Java中异常及异常的用法,讨论异常的基本特性、工作原理和一般结构,分析处理代码异常的职责。

接下来需要考虑的问题是:如何在代码中有效地应用这些知识?在处理异常时,我们有哪些选择?有哪些经验和最佳实践?第2章将回答这些问题。

 

2.1  简介

1章简要介绍了异常,阐述异常的结构和功能,讨论其在Java程序的工作原理。在实际中,为了在代码中有效处理异常,还必须了解出错时代码应如何响应,有哪些选项,以及为什么选择某种选项。换句话说,您必须回答下列问题:

       在处理异常时,有哪些可用选项?

       异常处理有哪些最佳实践?

       在异常处理代码中,要避免哪些问题?

本章将回答这些问题。讨论标准应用程序异常响应,权衡各种选择,介绍解决异常的最佳和最差实践。

 

2.2  选择处理或声明

由第1章可知,在代码中调用抛出异常的方法时,一般有两种选择:处理或声明异常。

“处理”还是“声明”

一般而言,若要传送信息,将错误消息发送到运行系统的其他部分,就声明异常;若无法在本地处理异常,或该异常在应用程序中的影响不限于单个方法,则声明异常。一个经验法则是:

“尽可能去处理异常,如果没有能力处理就声明异常。”

从本质上讲,仅当方法缺少自我处理异常的信息、上下文或资源时,才将异常信息传给调用者。

假定一个客户端应用程序要连到服务器,客户端有一个名为ClientNetwork的实用程序类,负责管理与服务器的通信。当客户端要连到服务器时,调用以下方法来建立通信连接:

public void connect(String server, int port) throws java.io.IOException

注意,连接方法抛出IOException。若方法调用失败,客户端应用程序该怎么办?按前述原理,若了解故障处理方式,则在代码中处理异常。例如,若有一个备份服务器,则可以尝试连接到备份服务器。

可采用多种方式来解决这个问题。如果不能连接到服务器,则可采用如下办法:

       等一会儿,再尝试连接。

       尝试连接到同一服务器的不同端口。

       尝试连接到另一个服务器。

       弹出一个对话框,问一下用户该怎么办。

       显示一条消息,指示连接尝试失败。

既然可以采用多种方法式来处理这个问题,当然也可将该方法交由调用者来处理。若如此,就声明异常,将异常传给方法的调用者。调用者负责选择正确的处理方式。由此可以看出,在试图选择“处理”还是“声明”异常时,有时确实面临两难境地。

在连接方法内部处理异常的“优点”是处理器代码与异常源同处一地。这很重要,在较复杂的应用程序中尤其如此。从长期看,代码将更易于维护;另外,方法调用者不需要编写处理器代码,因此更简单。

但这也存在“缺点”。连接方法代码缺少通用性,只能用于特定客户端实现。这还要求在方法中编写一定级别的应用程序逻辑,从而增加方法的复杂性。若要避免这些问题,并提高应用程序的灵活性,可能需要声明异常。

 

2.3  标准异常处理选项

前例介绍了在代码中处理异常的一些常见选项。下面列出一个更详细的列表,说明在catch块中处理异常时,有哪些标准选项。

对于处理器代码块捕获的大多数错误情况,一般可以采用以下9种响应方式:

       记录异常和相关信息。

       要求用户或应用程序输入信息。

       使用默认值或替换数据。

       将控制转移到应用程序的其他部分。

       将异常转换为其他形式。

       忽略问题。

       重试操作。

       采取替换或恢复操作。

       使系统作好停止准备。

注意,在处理代码时,不一定只用一个选项。有些情况可能要使用几个选项。例如,若客户端未连接到服务器,正确的操作序列可能是记录问题,再暂停重试。

2.3.1  记录异常和相关信息

为有效处理异常,日志记录(logging)是最有效的工具之一。这有利于系统的长期开发和维护,有助于完成系统恢复、测试和调试等任务。在Java中,有几种管理记录的方式。一般地,要记录信息,可使用以下的部分或所有方式:

       标准输出或标准错误流。

       自定义记录类。

       Java记录API

1. 标准输出或标准错误流

对于简单的记录任务,可使用标准输出或错误流:System.outSystem.err

1  System.out.println ("User error: replace user and continue");

2  System.err.println ("Press any key. Go on. I dare ya.");

因为System类允许通过方法调用System.setOut(PrintStream)System.setErr(PrintStream),将输出重定向到另一目标位置,所以能够满足基本文件输出等的需要。

此类功能一般适用于简单应用程序的本地记录。而对于较复杂的应用程序,使用这些功能工作量过大。此外,一些Java代码类型(特别是诸如企业JavaBeans的服务器端组件)运行在服务器的JVM中,不允许将输出定向到这些位置。

2. 自定义的记录类

一些应用程序要求记录更灵活,更易配置。此时,应为系统开发记录资源(即开发一个类)来接收应用程序范围内的调用,并将它们记录到一个中心位置。这样的类常实现为静态资源或单模式(Singleton),以确保通用于系统,而不需要其他对象包含其引用。

1  import java.io.*;

2  import java.util.*;

3

4  public class CustomLogger{

5     private static final String DEFAULT_FILE = "exceptions.log";

6     private static final String FILE_KEY = "application.logfile";

7     private static CustomLogger instance = new CustomLogger();

8     private PrintWriter outputLog;

9     private CustomLogger(){

10       String filename = System.getProperty(FILE_KEY, DEFAULT_FILE);

11       try{

12          outputLog = new PrintWriter(new FileWriter(filename, true));

13       }

14       catch (IOException exc){

15             exc.printStackTrace();

16       }

17     }

18      public static CustomLogger getInstance(){

19       return instance;

20     }

21     public void log(String message){

22       logMessage(new Date() + " " + message);

23     }

24     public void log(Throwable error){

25       StringBuffer message = new StringBuffer(new Date() +

26          " ERROR: " + error.getClass().getName() +

27          System.getProperty("line.separator"));

28       message.append(error);

29       logMessage(message.toString());

30     }

31     private void logMessage(String message){

32          outputLog.println(message);

33          outputLog.flush();

34     }

35   }

记录类适用于中型到大型应用程序,无论本地还是分布式系统,可用性都很高。不过,JDK1.4引入一种替换方法,即记录API,它通常比自定义的记录类更灵活更方便。

3. Java记录API

JDK1.4中,Sun引入了记录API,以更灵活有效地记录错误、消息和通知。一般地,使用java.util.logging包的几个类即可执行简单的记录任务。例如,若要将消息发送到标准输出,则代码如下所示:

3  Logger logException = Logger.getLogger("basic.exception.example");

4  logException.log(Level.WARNING, "Unable to find configuration file.");

也可方便地设置易于阅读的日志文件:

3  Logger logException = Logger.getLogger("exception.example");

4  try{

5     Handler fileOut = new FileHandler("exc.err", true);

6     fileOut.setFormatter(new SimpleFormatter());

7     logException.addHandler(fileOut);

8  }

9  catch (IOException ex){

10    // In this example, ignore the possible IOException for the Handler

11  }

12  // Additional application code...

13  logException.log(Level.WARNING, "Exception generated");

当然,前面都是简单演示。在大型应用程序中,可用记录API来开发极其复杂的架构。第5章将详细介绍记录API的用法。

2.3.2  要求用户或应用程序输入信息

对于与最终用户“接近”的问题,最好让用户来确定响应应用程序相应问题的方式。这一般通过GUI管理,使用户作出选择或输入信息。对于简单故障,用户可能仅需确定适当的操作序列;而对于较复杂的问题,则可能要添加附加或替换信息。很多GUI使用对话框来提示用户作出决策。在AWT中,可使用java.awt.Dialog类;在Swing API中,一般使用javax.swing. JDialogjavax.swing.JOptionPane。下面的示例代码显示了在出现错误时如何要求用户输入信息:

7  private void showConfigErrorMessage(){

8    String msg = "Unable to load user preferences file: create new file?";

9     String title = "Application Error";

10     int result = JOptionPane.showConfirmDialog(null, msg, title,

11       JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);

12     if (result == JOptionPane.YES_OPTION){

13       // User wants to create a config file; call createNewConfigFile()

14       createNewConfigFile();

15     }

16     else{

17       // User wants to use defaults; call loadDefaultSettings()

18       loadDefaultSettings();

19     }

20  }

在本例中,若在读取用户配置信息时出错,则将调用showConfigErrorMessage方法。通过该对话框,用户可以选择新建文件,或按默认设置执行。在较复杂的情况下,对话框可能允许用户执行一些更高级操作,如指定计算机上的配置文件位置。

并不总提示用户输入信息。在多数情况下,方法可以查询应用程序的其他部分,要求提供与适当后续操作相关的信息。

2.3.3  使用默认或替换数据值

如果使用替换或默认值,那么,即使在执行操作时遇到异常,程序仍可继续运行。在通信示例中,另一台服务器(或同一台服务器上的不同端口)可能是一个合适的替换方案。若有可识别的任何标准值,则可以在应用程序中包含默认值。在最简单的情况下,可以将这些值作为应用程序中的常量(静态最终值)

1  private static final String ALTERNATE_HOST ="denver";

2  private static final int ALTERNATE_PORT = 5280;

更复杂一些的选项是允许默认值存储在配置文件中,并在运行时加载到应用程序。JDK 1.2引入了Properties类,可轻易地完成这个任务。

1  private static final String ALTERNATE_HOST = "denver";

2  private static final String HOST_KEY = "client.app.host";

3

4  public void sendData(String host, int port,

5      Serializable information, String propertyFile){

6     if (communication == null){

7       communication = new ClientNetwork();

8     }

9     try{

10       communication.connect(host, port);

11       communication.sendData(information);

12     }

13     catch (IOException exc){

14       Properties serverProps = new Properties();

15       try{

16          FileInputStream input = new FileInputStream(propertyFile);

17          serverProps.load(input);

18          String serverName = serverProps.getProperty(HOST_KEY,

19             ALTERNATE_HOST);

20          sendData(serverName, port, information);

21       }

22       catch (IOException exc2){

23          exc.printStackTrace();

24       }

25    }

26  }

2.3.4  将控制传给应用程序的其他部分

您或许认为,声明异常是委托的终极方式:问题不再属于方法,处理任务将交给调用者。在下例中,若存在一些保存文件信息的问题,则saveOrderInfo会调用handleFileSaveError方法。在出现错误时,handleFileSaveError方法将解决文件I/O问题。

7  private void saveOrderInfo(OrderInfo info){

8     try{

9       OrderService.getInstance().saveOrderInfoToFile(info);

10     }

11     catch (IOException exc){

12       // Problem writing to a file; call handling method

13       handleFileSaveError(info);

14     }

15  }

也就是说,还有一种将异常处理职责传给系统另一部分的非终极方式:不是从异常产生方法完全委托,而是开发一个异常处理类,使用它来集中处理应用程序代码。

2.3.5  将异常转化为其他形式

有时,最好将异常转化为其他形式,以将异常更改为对应用程序更有意义的形式,提供更适当的上下文以准确描述错误。由于可将原始异常包装到另一个异常中(JDK 1.4开始),故不会失去原始异常的上下文或数据。下例显示解决saveOrderInfo方法产生的IOException的另一种方法:catch块将异常转化为OrderException抛给方法调用者。

9  private void saveOrderInfo(OrderInfo info) throws OrderException{

10     try{

11       OrderService.getInstance().saveOrderInfoToFile(info);

12     }

13     catch (java.io.IOException exc){

14      throw new OrderException("File I/O error when saving OrderInfo", exc);

15    }

16  }

2.3.6  忽略问题

注意,不能滥用这种方法,否则,代码将出现严重问题。确实存在这样的情况,即一个异常对应用程序的所有其他部分没有任何影响。例如,在调用I/O流的关闭方法时产生的异常便属于这种类型。该方法可抛出表示问题的IOException,但应用程序除了记录事件外,一般什么也不做。由于正试图首先关闭I/O流,故此类异常对代码或资源没什么影响。下面的示例代码是应用程序的一部分,它将普通文本文件回显到标准输出,在清理期间将调用文件流的关闭方法。若在关闭期间抛出IOException,则将忽略该异常:

15      // Declare member variable sourceFile in the class

16      private FileReader sourceFile;

17      // ...

18            try{

19               sourceFile.close();

20            }

21             catch (java.io.IOException exc){

22               // IOException while closing sourceFile

23               // Ignore, since it occurs during application shutdown

24             }

在本例中,应用程序可能已处理和记录读取文件时的标准异常。对于其余错误情况,忽略错误可能是合理的

2.3.7  重试操作

有些情况下,最适当的操作序列是在等一段时间后重试操作。在试图连接到服务器或数据库时,有时会发生异常,因为服务器的信息量过大。此时,最好再等一段时间,再尝试连接。

21 try{

22      clientNetwork.connect("www.talk-about-tech.com", 5280);

23   }

24   catch (java.io.IOException exc){

25     try{

26       Thread.sleep(10000);

27     }

28     catch (InterruptedException exc2){}

29     try{

30       clientNetwork.connect(“www.talk-about-tech.com”, 5280);

31     }

32     catch (java.io.IOException exc2){

33       // Retry failed; try an alternate strategy

34     }

2.3.8  采用替换或恢复操作

有时,可采用补偿方式来处理异常。例如,若不能连接到服务器,则可以在本地缓存数据,并在之后某一时间将数据发送到服务器。理想情况下,恢复操作将允许应用程序正常运行。如下列示例代码所示:

5        try{

6          // Try to connect to server for data transfer

7          svr.connect("www.talk-about-tech.com", 5280);

8        }

9        catch (IOException exc){

10          // Unable to connect to server; prepare to cache data locally

11          enableFileCache();

12        }

2.3.9  使系统作好停止准备

如果某一异常确实是应用程序的关键错误,则需要采取步骤,使系统作好停止准备。这种情况下,要确保该应用程序不致使系统的其他部分出现故障,也不会使数据处于不一致状态。这就需要完成以下几件事情:

       若有打开的文件,则关闭它。

       若有基于连接的资源,则采用普通方式关闭。

       若有需要保持一致的信息,则一定要保存。

       根据需要,通知应用程序、客户端或子系统应用程序将结束。

2.4  异常处理注意事项

前面介绍了处理异常的主要选项。下面将分析异常处理的一些基本注意事项。与大多数最佳实践一样,这些规则都是成熟的开发实践,除个别情况外,都必须严格遵守。如能贯彻始终,则处理器代码将更加有效。

2.5  处理异常时提倡的事项

大多数异常处理最佳实践着眼于识别特殊错误状况,并采取适当的处理操作。大多数规则实际上都是基本常识。

2.5.1  尽可能地处理异常

如开头部分所述,要尽量处理异常,如果条件确实不允许,无法在自己的代码中完成处理,就考虑声明异常。如果人为避免在代码中处理异常,仅做声明,则是一种错误和懒惰的实践。

2.5.2  具体问题具体解决

异常的部分优点在于能为不同类型的问题提供不同的处理操作。有效异常处理的关键是识别特定故障场景,并开发解决此场景的特定响应行为。为了充分利用异常处理能力,需要为特定类型的问题构建特定的处理器块。

2.5.3  记录可能影响应用程序运行的异常

至少要采取一些永久方式,记录下可能影响应用程序操作的异常。理想情况下,当然是在第一时间解决引发异常的基本问题。不过,无论采用哪种处理操作,一般总应记录下潜在的关键问题。别看这个操作非常简单,但可以帮助您用很少的时间来跟踪应用程序中复杂问题的起因。

2.5.4  根据情况将异常转换为业务上下文

构建异常成本不高,所以,若要通知一个应用程序特有的问题,有必要将应用程序转换为不同形式。若用业务特定状态表示异常,则代码更易维护。J2SE 1.4的异常有所增强,允许包装原始异常,故不会失去问题的原始上下文。

从某种意义上讲,无论何时准备将异常传到不同上下文(即另一技术层),都应将异常转换为对新上下文有意义的形式。

 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP