企业应用程序在构建时常常对异常处理关注甚少,这会造成对低级异常(如 java.rmi.RemoteException
和 javax.naming.NamingException
)的过度依赖。在 EJB 最佳实践的这篇专栏文章中,Brett McLaughlin 解释了为什么对异常处理投入一点关注就会给我们带来很大的帮助,并向您展示了两种简单技术,它们将帮助您正确地构建更健壮且有用的异常处理框架。
在本系列先前的技巧文章中,异常处理不属于讨论的核心范围之内。但是,您可能会发现一点,那就是我们一直都回避来自 Web 层的低级异常。我们向客户机提供诸如 ApplicationException
和 InvalidDataException
之类的异常,而没有让 Web 层处理象 java.rmi.RemoteException
或 javax.naming.NamingException
这样的异常。
远程和命名异常是 系统级异常,而应用程序和非法数据异常是 业务级异常,因为它们提交更适用的业务信息。当决定抛出何种类型的异常时,您应该总是首先考虑将要处理所报告异常的层。Web 层通常是由执行业务任务的最终用户驱动的,所以最好用它处理业务级异常。但是,在 EJB 层,您正在执行系统级任务,如使用 JNDI 或数据库。尽管这些任务最终将被合并到业务逻辑中,但是最好用诸如 RemoteException
之类的系统级异常来表示它们。
理论上,您可以让所有 Web 层方法预期处理和响应单个应用程序异常,正如我们在先前的一些示例中所做的一样。但这种方法不适用于长时间运行。让您的委派方法抛出更具体的异常,这是一个好得多的异常处理方案,从根本上讲,这对接收客户机更有用。在这篇技巧文章中,我们将讨论两种技术,它们将有助于您创建信息更丰富、更具体的异常,而不会生成大量不必要的代码。
嵌套的异常
在设计可靠的异常处理方案时,要考虑的第一件事情就是对所谓的 低级或 系统级异常进行抽象化。这些核心 Java 异常通常会报告网络流量中的错误、JNDI 或 RMI 问题,或者是应用程序中的其它技术问题。 RemoteException
、 EJBException
和 NamingException
是企业 Java 编程中低级异常的常见例子。
这些异常完全没有任何意义,由 Web 层的客户机接收时尤其容易混淆。如果客户机调用 purchase()
并接收到 NamingException
,那么它在解决这个异常时会一筹莫展。同时,应用程序代码可能需要访问这些异常中的信息,因此不能轻易地抛弃或忽略它们。
答案是提供一类更有用的异常,它还包含低级异常。清单 1 演示了一个专为这一点设计的简单 ApplicationException
:
清单 1. 嵌套的异常
package com.ibm;
import java.io.PrintStream;
import java.io.PrintWriter;
public class ApplicationException extends Exception {
/** A wrapped Throwable */
protected Throwable cause;
public ApplicationException() {
super("Error occurred in application.");
}
public ApplicationException(String message) {
super(message);
}
public ApplicationException(String message, Throwable cause) {
super(message);
this.cause = cause;
}
// Created to match the JDK 1.4 Throwable method.
public Throwable initCause(Throwable cause) {
this.cause = cause;
return cause;
}
public String getMessage() {
// Get this exception's message.
String msg = super.getMessage();
Throwable parent = this;
Throwable child;
// Look for nested exceptions.
while((child = getNestedException(parent)) != null) {
// Get the child's message.
String msg2 = child.getMessage();
// If we found a message for the child exception,
// we append it.
if (msg2 != null) {
if (msg != null) {
msg += ": " + msg2;
} else {
msg = msg2;
}
}
// Any nested ApplicationException will append its own
// children, so we need to break out of here.
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
// Return the completed message.
return msg;
}
public void printStackTrace() {
// Print the stack trace for this exception.
super.printStackTrace();
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
System.err.print("Caused by: ");
child.printStackTrace();
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintStream s) {
// Print the stack trace for this exception.
super.printStackTrace(s);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
s.print("Caused by: ");
child.printStackTrace(s);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintWriter w) {
// Print the stack trace for this exception.
super.printStackTrace(w);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
w.print("Caused by: ");
child.printStackTrace(w);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public Throwable getCause() {
return cause;
}
}
|
清单 1 中的代码很简单;我们已经简单地将多个异常“串”在一起,以创建单个、嵌套的异常。但是,真正的好处在于将这种技术作为出发点,以创建特定于应用程序的异常层次结构。异常层次结构将允许 EJB 客户机既接收特定于业务的异常也接收特定于系统的信息,而不需要编写大量额外代码。
异常层次结构
异常层次结构应该从一些十分健壮而又通用的异常入手,如 ApplicationException
。如果您将顶级异常搞得太具体,那么其结果是您今后将不得不重新构造层次结构,以适应某些较通用的情况。
因此,让我们假定您的应用程序要求 NoSuchBookException
、 InsufficientFundsException
和 SystemUnavailableException
。您不必创建这三个异常,让它们继承 ApplicationException
,然后只需提供极少几个必须的构造器来创建格式化的消息。清单 2 是此类异常层次结构的示例:
清单 2. 异常层次结构
package com.ibm.library;
import com.ibm.ApplicationException;
public class NoSuchBookException extends ApplicationException {
public NoSuchBookException(String bookName, String libraryName) {
super("The book '" + bookName + "' was not found in the '" +
libraryName + "' library.");
}
}
|
当需要编写大量专用异常时,异常层次结构极大地简化了工作。对于一个异常,为每个异常类添加一个或两个构造器,所花费时间很少不超过几分钟。您还经常需要给这些更具体的异常(这些异常也是主应用程序异常的子类)提供子类,以提供更具体的异常。例如,您可能需要 InvalidTitleException
和 BackorderedException
来继承 NoSuchBookException
。
企业应用程序在构建时通常都不会注意异常处理。尽管依靠低级异常(如 RemoteException
和 NamingException
)很容易(有时也很诱人),但如果一开始就建立一个可靠的、深思熟虑的异常模型,则您将在应用程序上少花很多精力。创建一个嵌套的、层次结构化的异常框架将改进代码的可读性及其可用性。
分享到:
相关推荐
"android-crash"框架,尽管已被废弃,但仍然能为我们提供一些关于如何构建崩溃报告和异常处理系统的见解。 一、Android程序崩溃与异常处理基础 在Android系统中,程序可能会因为各种原因如空指针异常...
在Java编程语言中,异常处理是程序健壮性的重要组成部分。异常框架设计是确保软件能够优雅地处理错误和异常情况的关键。...通过阅读文档`java异常框架处理.doc`,可以获取更多详细信息和实际示例。
### 异常处理的解决方案 #### 错误与异常处理概览 在软件开发中,错误和异常处理是一项至关重要...通过合理的异常处理设计,不仅可以避免程序崩溃,还可以为用户提供友好的错误提示,帮助他们更好地理解和解决问题。
4. **自定义异常类**:创建自定义异常类可以帮助我们更好地组织和分类应用中的错误。例如,可以定义一个`InvalidInputException`,当用户输入无效时抛出,以便在不同地方捕获并处理。 5. **使用`ActionError`和`...
本文将深入探讨一个简单纯净的Web框架——S2SH(Struts2 + Spring + Hibernate),并结合JDBC、Ant构建项目,以及异常处理机制,为初学者提供一个清晰的学习路径。 首先,让我们了解S2SH框架的核心组件: 1. **...
通过以上方法,Struts2能够提供灵活且强大的异常处理能力,使得开发者能够更好地控制和管理应用程序的异常行为,提升用户体验,并简化故障排查工作。结合提供的压缩包文件"struts2_003",可能包含了示例代码或者项目...
本压缩包“基于python构建的自动化测试框架.zip”提供了一个使用Python语言实现的自动化测试框架示例,旨在帮助开发者和测试工程师更好地理解和应用自动化测试。 首先,Python是一种流行的编程语言,它简洁明了的...
构建一个PHP框架是一个深入理解PHP工作原理和技术架构的过程,它能帮助开发者更好地组织代码,提高开发效率,并且便于团队协作。下面将详细讲解从零开始构建PHP框架的关键步骤和技术要点。 1. **基础架构设计** - ...
在Struts中,异常处理是一个关键部分,它帮助开发者优雅地管理可能出现的错误和异常,提供更好的用户体验。 声明式异常处理是Struts中的一种特性,允许我们在struts.xml配置文件中定义全局的异常映射,而不是在每个...
为了更好地管理和响应不同类型的异常,建议构建一套异常层次结构。例如,定义基类`BaseException`,并根据业务需求扩展多个子类,如`BusinessException`、`SystemException`等,以便于在异常拦截器中进行更细致的...
ThinkPHP5.1是基于PHP语言的一个轻量级、高性能的国产PHP框架,它提供了丰富的特性,包括优雅的MVC模式、强大的路由系统以及完善的异常处理等,帮助开发者更高效地构建Web应用。 描述中提到的具体使用参考链接是一...
为了提供更精细的控制和更好的用户体验,开发者可以自定义错误处理。这可以通过实现`IErrorHandler`接口来完成,允许在服务端捕获异常并决定如何响应。此外,还可以通过配置文件调整错误行为,例如设置`...
6. **数据预处理**:在使用nupic之前,可能需要对原始数据进行清洗和转换,例如去除噪声、填充缺失值、标准化数据等,以便模型更好地学习和预测。 7. **模型训练与评估**:训练nupic模型需要一个带有标签的训练集,...
异常处理是计算机编程中不可或缺的一部分,它涉及到程序在遇到错误或意外情况时的恢复机制。...通过学习这些理论和实践,开发者可以更好地构建稳健的系统,增强程序的容错能力,从而提高软件的整体质量。
通过阅读这些资料,开发者可以提升自己的专业技能,更好地应对开发中的异常处理挑战。 总的来说,C++异常处理机制不仅涉及语言层面的语法,还包括底层的二进制数据结构和编译器内部的工作原理。深入学习这一主题,...
ASP.NET MVC是一个强大的Web应用程序开发框架,其可扩展性使得开发者可以轻松地集成第三方库,如Enterprise Library(EntLib)的异常处理应用块,来构建更完善的异常处理机制。在本文中,我们将深入探讨如何在ASP...
MFC提供了异常处理机制,可以通过try-catch块来捕获和处理这些异常。 9. **资源管理**:MFC有内置的资源管理机制,可以方便地加载和使用位图、图标等资源。这些资源可以用于定义按钮、菜单项的外观。 10. **界面...
其次,通过自定义Action处理异常,我们可以更好地控制和展示错误信息。例如,我们创建一个模拟用户登录的场景,定义一个`LoginInfoModel`,包含用户名和密码字段,并添加数据验证特性。接着,我们创建一个`...
在描述中提到的“包”(package)是Java中的一个重要概念,它用于组织类和接口,帮助我们更好地管理代码,避免命名冲突。通过导入所需的包,我们可以使用其中定义的类和接口。例如,`java.util`包包含了各种常用的...
泛型是Java语言中的一个重要特性,它允许在编译时检查类型安全,同时提供更好的性能。在描述中提到的3-4和3-5两部分,主要讲解了泛型的基础概念、使用方法和高级用法。泛型能够帮助我们编写更加灵活和可重用的代码...