When you open a lot of dynamic resources, are you tired of maintaining the finally block with excessive try - close - catch boilerplate? Does your project contain a lot of code that looks like this? Wouldn't it be nice if you could close(Connection, Statement, ResultSet) or close(ResultSet, Statement, Connection) or in fact call close on "Anything"‽ with a close method using
"duck" typing?
java.sql.Connection conn = null;
java.sql.Statement stmt = null;
java.sql.ResultSet rs = null;
try {
while (rs.next()) {
}
} catch (SQLException e) {
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
You can fix that boiler plate with this Close class!
/*
* Copyright © 2013 - Elliott Frisch
*
* THIS SOFTWARE IS PROVIDED UNDER THE CREATIVE COMMONS
* LICENSE 3.0 "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
* A PARTICULAR PURPOSE.
*
* To use this software you must agree to the complete
* license terms available at:
* http://creativecommons.org/licenses/by/3.0/us/deed.en_US
*
* It is the intent of the author(s) that you may use or
* modify this software for any purpose (including your own
* commercial gain) provided that this notice remains in its
* entirety.
*
* Created by Elliott Frisch - www.frischcode.com
*/
package com.frischcode.util;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.TreeSet;
/**
* <b>Rationale:</b> Frequently you're utilizing dynamic
* resources, and you need those resources to be closed when
* you're finished with them. <br />
*
* <b>Common Examples:</b>
* <ul>
* <li>Performing JDBC Queries</li>
* <li>Writing to File(s)</li>
* <li>Writing to Stream(s)</li>
* <li>Reading from Stream(s)</li>
* <li>Etc.</li>
* </ul>
*
* <b>Note:</b> This class consists of only one public
* static final method and it is not necessary to perform
* instantiation. Import static on the close method and
* <i>please</i> enjoy.
*
* @author Elliott Frisch
*/
public final class Close {
/**
* Provide a simple demonstration.
*
* @param args
*/
public static void main(String[] args) {
close(new AnythingTestClass());
}
/**
* Call close on the provided objects while suppressing
* exceptions and guaranteeing that the objects will be
* closed in the following order -
* <ol>
* <li>java.sql.ResultSet(s)</li>
* <li>java.sql.Statement(s)</li>
* <li>java.sql.Connection(s)</li>
* <li>java.io.Closeable(s)</li>
* <li>"Anything"‽ with a close method through
* "duck" typing</li>
* </ol>
*
* @param objects
* Any number of objects (of any type) to close.
*/
public static final void close(
final Object... objects) {
if (objects == null || objects.length == 0) {
return;
} else if (objects.length == 1) {
final Object obj = objects[0];
if (obj != null) {
if (obj instanceof ResultSet) {
close((ResultSet) obj);
} else if (obj instanceof Statement) {
close((Statement) obj);
} else if (obj instanceof Connection) {
close((Connection) obj);
} else if (obj instanceof Closeable) {
close((Closeable) obj);
} else {
close(obj);
}
}
return;
}
final Set<ResultSet> rsSet = new TreeSet<ResultSet>();
final Set<Statement> stmtSet = new TreeSet<Statement>();
final Set<Connection> connSet = new TreeSet<Connection>();
final Set<Closeable> closeableSet = new TreeSet<Closeable>();
final Set<Object> objSet = new TreeSet<Object>();
for (final Object obj : objects) {
if (obj == null) {
continue;
}
if (obj instanceof ResultSet) {
rsSet.add((ResultSet) obj);
} else if (obj instanceof Statement) {
stmtSet.add((Statement) obj);
} else if (obj instanceof Connection) {
connSet.add((Connection) obj);
} else if (obj instanceof Closeable) {
closeableSet.add((Closeable) obj);
} else {
objSet.add(obj);
}
}
for (final ResultSet rs : rsSet) {
close(rs);
}
for (final Statement stmt : stmtSet) {
close(stmt);
}
for (final Connection conn : connSet) {
close(conn);
}
for (final Closeable closeable : closeableSet) {
close(closeable);
}
// Close the "Antyhing"(s)‽
for (final Object obj : objSet) {
close(obj);
}
}
private static final void close(final ResultSet rs) {
if (rs != null) {
try {
if (rs.isClosed()) {
return;
}
rs.close();
} catch (final SQLException ignored) {
}
}
}
private static final void close(final Statement stmt) {
if (stmt != null) {
try {
if (stmt.isClosed()) {
return;
}
stmt.close();
} catch (final SQLException ignored) {
}
}
}
private static final void close(final Connection conn) {
if (conn != null) {
try {
if (conn.isClosed()) {
return;
}
conn.close();
} catch (final SQLException ignored) {
}
}
}
private static final void close(final Closeable c) {
if (c != null) {
try {
c.close();
} catch (final IOException ignored) {
}
}
}
/**
* Close the "Anything"‽ Reflect on the object. Does
* it have a parameterless close method? If so, call close
* on that object!
*
* @param anything
* The "Anything"‽ to close.
*/
private static final void close(final Object anything) {
if (anything == null) {
return;
}
final Class<?> cls = anything.getClass();
try {
final Method m = cls.getMethod("close",
EMPTY_CLASSES);
if (m != null) {
m.invoke(anything, EMPTY_OBJECTS);
}
} catch (final Exception ignored) {
}
}
private static final Class<?>[] EMPTY_CLASSES = //
new Class<?>[] {};
private static final Object[] EMPTY_OBJECTS = //
new Object[] {};
private static class AnythingTestClass {
private AnythingTestClass() {
System.out.println("Anything\u203d"
+ "TestClass Constructed");
}
/*
* In this case static analysis (i.e. Eclipse) is
* @WRONG.
*/
@SuppressWarnings("unused")
public void close() {
System.out.println("Inside the Anything\u203d"
+ "TestClass.close() method.");
}
}
// Help against "accidents".
private Close() {
super();
}
}
No comments :
Post a Comment