诊断Java代码: 空标志错误模式

空标志错误模式

在我的上一篇文章中,我说明了用空指针代替各种不同基本类型的数据是如何成为引起 NullPointerException 异常最普遍的原因之一的。这一次,我将说明用空指针代替异常情况怎么也会导致问题的出现。在 Java 程序中,异常情况通常是通过抛出异常,并在适当的控制点捕获它们来进行处理。但是经常看到的方法是通过返回一个空指针值来表明这种情况(以及,可能打印一条消息到 System.err )。如果调用方法没有明确地检查空指针,它可能会尝试丢弃返回值并触发一个空指针异常。

您可能会猜想,之所以称这种模式为空标志错误模式,是因为它是不一致地使用空指针作为异常情况的标志引起的。

起因

让我们来考虑一下下面的这个简单的桥类(从 BufferedReaders 到 Iterators ):

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Iterator;
public class BufferedReaderIterator implements Iterator {
  private BufferedReader internal;
  public BufferedReaderIterator(BufferedReader _internal) {
   this.internal = _internal;
  }
  public boolean hasNext() {
   try {

    boolean result = true;
    // Let's suppose that lines in the underlying input stream are known
    // to be no greater than 80 characters long.
    internal.mark(80);
    if (this.next() == null) {
     result = false;
    }
    internal.reset();
    return result;
   }
   catch (IOException e) {
    System.err.println(e.toString());
    return false;
   }
  }
  public Object next() {
   try {
    return internal.readLine();
   }
   catch (IOException e) {
    System.err.println(e.toString());
    return null;
   }
  }
  public void remove() {
   // This iterator does not support the remove operation.
   throw new UnsupportedOperationException();
  }
}

时间: 2024-10-12 07:02:18

诊断Java代码: 空标志错误模式的相关文章

诊断Java代码: Broken Dispatch错误模式

整体和部分 还记得这条谚语吗,"整体大于部分之和"?如果把一个个独立的事件组合成一个相互作用的整体,产生的结果会比单个个体的作用之和要大得多. 程序也是一样的道理.随着一个个新方法被添加到程序中,整个程序可能的控制流程迅速增加.对于大型程序而言,很快局面就会无法控制了.就象是一个荒谬而又不可思议的戏法,有时您得到的最终结果并不是您所期望的方向 ― 这同您在重载方法或者覆盖方法时遇到的情况有些类似. Broken Dispatch 错误模式 面向对象语言的最强大的特性之一就是继承多态性.

诊断Java代码: Impostor Type错误模式

当使用字段中特殊的标记来区别对象类型时,可能会产生标记对相关数据误贴标签的错误 ― 通称为 Impostor Type 错误模式.在诊断 Java 代码的这一部分中,Eric Allen 对这个错误的症状和起因进行了分析,详细说明了预防错误发生的方法,并讨论了一种吸引人的混合实现方法,这种方法不使用 impostor type,但最后,还是有很多相同的缺点产生.请在 讨论论坛与作者及其他读者分享您对本文的看法. 程序中除了最无关紧要的部分外都要对某些数据类型进行操作.静态类型系统提供了一种方法,

诊断Java代码: 臆想实现错误模式,第2部分

臆想实现重温 回想一下 上次接口的 臆想实现是一个合法的实现,但不满足接口规范的某些未经检查的方面.我们考虑一下下面的堆栈接口,以及许多未被其单独的类型签名捕获的不变量: 清单 1. 一个堆栈接 public interface Stack { public Object pop(); public void push(Object top); public boolean isEmpty(); } 例如,请考虑我们希望任意堆栈实现都遵守的下列规则: 如果一个对象 o 被压进堆栈 s ,且在堆栈

诊断Java代码: Double Descent错误模式

不要强制转换这个类! 与可怕的 空指针异常(该异常除了报告空指针之外,对于将要发生的事情什么也不说)不同,类强制转换异常相对来说容易调试. 类强制转换经常发生在递归下行数据结构的程序中,通常是当代码的某些部分在每次方法调用中下行了两级且在第二次下行时调度不当时发生的.程序员可通过学习 Double Descent 错误模式来识别这种问题. Double Descent 错误模式 本周的专题是 Double Descent 错误模式.它通过类强制转换异常来表明.它是由递归下行复合数据结构引起的,这

诊断Java代码: Liar View错误模式

Liar, liar! 设想一下:您已经为一个分布式系统精心设计了一个极好的 GUI 程序,它包含了客户机请求的所有东西及其它一些东西.您已经让它运行通过了一个自动化测试套件的测试 ― 由于不变量的数量是个天文数字,因此,自动化测试是必须的.测试的结果是程序获得了一张"无错误的健康证明书". 发布这个 GUI 的期限到了,但是,作为一个象您这样严格的程序员,只是为了发现错误的行为 ― 本该在自动化测试中就被捕捉到的行为,您启动了程序,对它做最后一次手工测试.但愿您能够避免这种情形.真的

诊断Java代码: Fictitious Implementation错误模式,第1部分

Java 语言接口是一种强大的工具.它具有多继承的很多优点,而没有什么问题.为客户希望使用的所有服务指定一个接口,使得在需要时插进这种接口的不同实现成为可能. 遗憾的是,规范中可以被表达的部分只有方法说明.对任何实现来说,很可能还有很多其它不变量希望被掌握,但是 Java 语言没有提供检查它们的工具. 臆想错误模式 由于这种限制,很可能"实现"了一个接口而实际上没有满足预期的语义.由这种 Fictitious Implementation导致的错误就是本周专栏的主题. 例如,请看一看下

诊断Java代码

诊断Java代码: Broken Dispatch错误模式 诊断Java代码: Double Descent错误模式 诊断Java代码: Impostor Type错误模式 诊断Java代码: Java编程中的断言和时态逻辑 诊断Java代码: Liar View错误模式 诊断Java代码: Repl提供交互式评价 诊断Java代码: 单元测试与自动化代码分析协同工作 诊断Java代码: 将时态逻辑用于错误模式 诊断Java代码: 进行记录器测试以正确调用方法 诊断Java代码: 空标志错误模式

诊断Java代码:孤线程(Orphaned Thread)错误模式

在多线程代码中,使用驱动其它线程所负责的动作的单个主线程是常见的.这个主线程发送消息,通常是通过把它们放到一个队列中,然后其它线程处理这些消息.但是如果主线程抛出一个异常,那么剩余的线程会继续运行,等待更多输入到该队列,导致程序冻结.在诊断 Java 代码的这一部分中,专职 Java 开发者兼兼职捉虫者 Eric Allen 讨论检测.修复和避免这一错误模式. 用多线程编写代码对程序员大有好处.多线程能使编程(和程序)进行得快得多,而且代码能有效得多地使用资源.然而,跟生活中的很多事情一样,多线

诊断Java代码: 进行记录器测试以正确调用方法

用 JUnit进行单元测试是一个功能强大的方法,它可以确保您的代码基础的完整性,但是一些不变量比其他(方法调用序列是其中一种)更难测试.在诊断Java 代码这一部分,Eric Allen描述了怎样在您的单元测试中使用记录器(一种特殊的侦听器),来确保一个方法调用序列按恰当的顺序发生.请点击文章顶部和底部的 讨论,与作者和其他读者在论坛上分享您关于本文的看法. 随着时间的推移,当系统开发人员,维护人员甚至是系统详细说明改变时,JUnit 框架提供一个很好的方法来改善系统的坚固性.通过测试,您可以检