One feature of the Java programming language is storage automation, which frees programmers from the error-prone process of releasing used memory. However, many programs still have to deal with resource issues, such as file and database connections, which must be explicitly released after use. As with manual management of storage, programmers make many mistakes in managing resources manually. One of these is the theme ―split cleaner error pattern for this week's column.
To separate or not to separate
When managing resources such as files and database connections, you must release them after you have used the resources. Of course, for any specified execution of the code, you want to get the resource once and then release it at once. To do this, you can use two ways:
You can obtain and release resources in the same method. In this way, the resource can be guaranteed to be released once each time it is obtained.
You can track every possible execution path for your code and make sure that resources are finally freed in each instance.
The second way can be problematic. Because your code base is inevitably getting bigger, another programmer who is unfamiliar with your code may add a path of execution that does not release the resource, and the consequence is a resource leak, of course.
Split Cleaner Error mode
I refer to the error that fits this pattern as split cleaner because the code that frees the resource is separated by various possible execution paths. Because the release code along each path is likely to be the same, most split cleaner are also examples of rogue tile. (Rogue tile is my nickname for a mistake that was originally written in copy and paste, but then forgot to modify all copies of the code appropriately after making some changes.) For more information on rogue tile, refer to my paper "Error mode: Introduction." ”)
For example, suppose you are working with JDBC on a list of employee names. Many of the operations that you want to perform include traversing the table and calculating the data contained therein. The last action you want to complete may be to print out the names of all employees, as follows:
Listing 1. Code to traverse an employee table
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);
}
}
First of all, Han digression. Notice that I have extracted the code used to traverse the table and put it in the abstract class Walker so that the new subclass can easily traverse the rows in the table. While it is often a waste of time to try to predict the various ways in which a program is extended and write code for it, let's assume that in this case there is absolutely, no doubt, an extension of this type of code in any case. (In fact, I can guarantee that there will only be such an extension before the end of this article).