It is possible that an exception gets thrown in the finally block even though it escapes detection at compile time. This can prevent other clean-up statements from getting executed.
Non-Compliant Code Example
The finally clause closes the reader object in this non-compliant example. However, it is incorrectly assumed that the statements within the finally block cannot throw exceptions. Notably, close() can throw an IOException which in turn prevents any subsequent clean-up lines from getting executed. This is not detected at compile time since close() throws the same exception type as read or write.
class Login {
static void checkPassword(String password_file) throws IOException {
StringBuffer fileData = new StringBuffer(1000);
BufferedReader reader = new BufferedReader(new FileReader(password_file));
try {
int n;
char[] passwd = new char[1024];
while ((n = reader.read(passwd)) >= 0) {
String readData = String.valueOf(passwd, 0, n);
fileData.append(readData);
passwd = new char[1024];
}
String realPassword = "javac<at:var at:name="f3b" />b3";
System.out.println(fileData.toString());
if (fileData.toString().equals(realPassword)) {
System.out.println("Login successful");
}
else {
System.out.println("Login failed");
}
} finally {
reader.close();
//other clean-up code
}
}
public static void main(String[] args) throws IOException {
String path = "c:\\password.txt";
checkPassword(path);
}
}
Compliant Solution
This compliant solution correctly places the close() statement in a try-catch block. Thus an IOException can be handled without letting it propagate any further.
class Login {
static void checkPassword(String password_file) throws IOException {
StringBuffer fileData = new StringBuffer(1000);
BufferedReader reader = new BufferedReader(new FileReader(password_file));
try {
int n;
char[] passwd = new char[1024];
while ((n = reader.read(passwd)) >= 0) {
String readData = String.valueOf(passwd, 0, n);
fileData.append(readData);
passwd = new char[1024];
}
String realPassword = "javac<at:var at:name="f3b" />b3";
System.out.println(fileData.toString());
if (fileData.toString().equals(realPassword)) {
System.out.println("Login successful");
}
else {
System.out.println("Login failed");
}
} finally {
try { //enclose in try-catch block
reader.close();
//other clean-up code
}catch (IOException ie) {ie.getMessage()}
}
}
public static void main(String[] args) throws IOException {
String path = "c:\\password.txt";
checkPassword(path);
}
}
References
Java Puzzlers 5.41
Java I/O