Welcome 微信登录

首页 / 软件开发 / JAVA / 诊断Java代码::Split Cleaner错误模式

诊断Java代码::Split Cleaner错误模式2011-02-10 IBM Eric E. AllenJava 编程语言的一个特色是存储自动管理,它把程序员从很容易出错的释放使用后的内存的工作中解放出来。尽管如此,许多程序还是得处理资源问题,例如文件和数据库连接,这些都必须在使用之后明确地释放掉。跟手工管理存储一样,程序员在手工管理资源时也会犯很多错误。其中一个就是本周专栏的主题 ― Split Cleaner错误模式。

分开还是不分开

在管理诸如文件和数据库连接这样的资源时,您必须在使用完资源后把它释放掉。当然,对代码的任何指定的执行,您希望一次获得资源,然后一次将其释放。要做到这点,您可以采用两种方式:

您可以在同一个方法中获得并释放资源。用这种方式,可以保证资源每获得一次,也释放一次。

您可以跟踪代码的每一个可能的执行路径,并确保在每一个实例中资源最后都被释放掉了。

第二种方式可能会出问题。因为您的代码库不可避免地要变大,另一个不熟悉您代码的程序员或许会添加一条没把资源释放掉的执行路径,其后果当然是资源泄漏。

Split Cleaner 错误模式

我把符合这种模式的错误称为 split cleaner,是因为释放资源的代码是沿各种可能的执行路径分开的。因为沿各条路径的释放代码很可能都是一样的,所以大多数 split cleaner 也是 rogue tile的例子。(Rogue tile 是我对一种错误的称呼,这种错误的起因是:起初用拷贝和粘贴的方式编写代码,但后来在做了一些更改后却忘了适当地修改代码的所有副本。如想更多了解 rogue tile,请参阅我的论文“ 错误模式:介绍。”)

例如,假设您正用 JDBC 处理一张员工姓名表。您希望执行的许多操作中包括遍历这张表并对其中包含的数据进行计算。您要完成的最后一个操作可能是打印出所有员工的名字,如下所示:

清单 1. 遍历一个员工表的代码

import java.sql.*;
public class Example {
public static void main(String[] args) {
String url = "your database url";
try {
Connection con = DriverManager.getConnection(url);
new TablePrinter(con, "Names").walk();
}
catch (SQLException e) {
throw new RuntimeException(e.toString());
}
}
}
abstract class TableWalker {

Connection con;
String tableName;
public TableWalker(Connection _con, String _tableName) {
this.con = _con;
this.tableName = _tableName;
}
public void walk() throws SQLException {
String queryString =("SELECT * FROM " + tableName);
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(queryString);

while (rs.next()) {
execute(rs);
}
con.close();
}
public abstract void execute(ResultSet rs) throws SQLException;
}
class TablePrinter extends TableWalker {

public TablePrinter(Connection _con, String _tableName) {
super(_con, _tableName);
}
public void execute(ResultSet rs) throws SQLException {
String s = rs.getString("FIRST_NAME");
System.out.println(s);
}

}

先说点题外话。请注意,我已把用来遍历表的代码抽出来放到了抽象类 Walker 中,以使新的子类可以很容易地遍历表中的行。虽然试图预测程序被扩展的各种方式并为其编写代码通常是浪费时间,但还是让我们假设在此例中 绝对地,毫无疑问地,无论如何对代码只做这一类的扩展。(事实上,我可以保证在本文结束前,只会有这样一种扩展)。