+6  A: 

I'd avoid the following

   sql.append("SELECT * FROM ").append("dogs_table");
   sql.append(" WHERE ").append(colName).append("='");
                        sql.append(colValue).append("'");

and instead use a PreparedStatement with its associated parameter setter methods (setString()) etc. This will prevent problems with values for colValue having quotes, and SQL injection attacks (or more generally, colValue forming some SQL syntax).

I would never return a null if the collection was merely empty. That seems very counter-intuitive, and completely unexpected from the client's point of view.

I wouldn't recommend returning a null in error conditions, since your client has to explicitly check for this (and will probably forget). I would return an empty collection if need be (this may be analogous to your comment re. a null object), or more likely throw an exception (depending on the circumstances and the severity). The exception is useful in that it will carry some information relating to the error encountered. Null tells you nothing.

What should you do if encountering a problem whilst building a Dog object ? I think that depends on how robust and resilient you want your application to be. Is it a problem to return a subset of Dogs, or would it be completely catastrophic and you need to report this ? That's an application requirement (I've had to cater for either scenario in the past - best-effort or all-or-nothing).

A couple of observations. I'd use HashMap rather than the old Hashtable (synchronised for all access and , more importantly, not a proper Collection - if you have a Collection you can pass it to any other method expecting any Collection), and StringBuilder over StringBuffer for similar reasons. Not a major problem, but worth knowing.

Brian Agnew
+1 for `PreparedStatement` and for using `HashMap` over `Hashtable`. There's no good reason to use `Hashtable` in modern code. And any time you build SQL manually as strings you set yourself up for all kinds of SQL injection vulnerabilities.
Daniel Pryden
Throwing an exception here, in my opinion will add no value to my code, as it needs to be catched on a higher level (wich we can forget to do) and will tell me nothing more, as i already logged the error details. Should the user be prompted or not here that an error has occured?
Hypercube
Can u please translate that StringBuffer creation code into PreparedStatement version, to clearly mark the differences? And btw, what can go wrong with the StringBuffer forming the query, if the creator is paying enough attention to it?
Hypercube
I dunno about the HashMap..i've google it and founded this : http://www.coderanch.com/t/202040/Performance/java/Hashtable-vs-HashMap. Slight performance increase vs. loosing thread-safe atribute doesnt pay off.
Hypercube
I would use it just for the fact that it implements java.util.Collection and can be passed to any method taking Collections
Brian Agnew
I too would recommend the PreparedStatement, but since you are concerned with improving your techniques(and maybe even optimizing it to be more efficient)then there is also a possible downside to using PreparedStatement.PreparedStatement although more often then not has shown to be successful in optimizing and making it more efficient, it has also shown in some circumstances, to have a larger overhead then simply just putting it together how you have done it originally. I am not quite sure on the exact reason of the overhead, but if you are interested in PreparedStatement, consider this.
CitadelCSAlum
Thanks, i will. I have made some tests using PreparedStatement, and a problem arised : i wanna use static objects like Connection, Statement, etc to refer to database. Using PreparedStatement, that sounds impossible, as a new object must be constructed every time. Further more, PMD code analizer suggests that the newly created PS may not close normally. Closing PS in the finally clause will throw an exception (OperationNotAllowed..resultset closed) to the caller method. I am a bit stuck here. Should i even care for SQL injection if this is NOT a web-based app?
Hypercube
PreparedStatement will also handle quoting of strings. e.g. in your example code, what happens if you try to insert a string with a single quote ? Get a new connection each time, then get a new PreparedStatement etc. each time.
Brian Agnew
A new connection each time?? I found that hard to believe like the best thing to do. If your app has 50 or 100 users or more, what will happen if every one of them spawn a new connection witch each little thing they do?? This looks like the road to hell man :-(. A connection once initialised could be re-used and this single connection will be able to create as many new PeparedStatements as i need. I cannot agree with your suggestion here.
Hypercube
You need to investigate connection pooling. When you get a new connection it will pull an existing connection from the pool, so it's not really new.
Brian Agnew
Yes, connection pooling is a more appropriate solution. However, perhaps a bit too much, to implement connection pooling just to be able to use a new PreparedStatement. Again, if i have a static Connection object called con and i call con.createPreparedStatement(someQuery) every time wouldn't suffice? I dont care much about SQL Injection here, as i wont create queries directly from parsing user input.
Hypercube
+3  A: 

Null Object Pattern is a design pattern where you always return an object to avoid NPE:s and any null checks in your code. In your case this means that instead of returning null, return an empty Hashtable<Long, Dogs> instead.

The reasoning is that since it's a collection and your other code will access it as such, it won't break down if you return an empty collection; it won't be iterated through, it won't contain anything surprising, it wont cause NPE:s to be thrown and whatnot.

To be precise, a Null Object is a special implementation of a class/interface which does absolutely nothing and thus has no side effects of any kind. Because of its nature of not being null using it will make your code cleaner since when you know that you'll always get an object from your method calls no matter what happens inside the method you don't even have to check for nulls nor make code reacting to them! Because Null Object doesn't do anything, you can even have them as singletons just lying around and thus save memory by doing that.

Esko
Thank u for clearing that up. It looks like a special Class can be built with static initializers for Null Objects, like these : final static String[2] EMPTY_STRING_ARRAY = new String[]{"", ""}, right?
Hypercube
Esko
Roger that. What if my object X is hand-maded, has Y fields and Z methods? I must write a class named NullX with Y "default" or "null" values and Z empty methods, to substitute the original object? That also implies an interface to be created. Isn't that too much trouble? Using new X() with default values cannot do the same thing (except for the extra memory consumed with each instance?). Or perhaps i can make THIS object (new X - my null object) a static variable somewhere, to call in all cases?
Hypercube
A bit confusing but as far as I understood, that'd be the Singleton. Considering Null Object Pattern in POJOs and beans, yes it means you have to implement Null Objects to fields and such too, but most commonly replacing null String with "" and numbers with -1 or 0 is enough.
Esko
I've readed about the possible implementations of the NullObjects : there are 2 main ones..1. Using an interface, 2.the Null Object will extend the RealObject, and therefore will have to implement his methods. There are SERIOUS concerns against this pattern <a href ="http://blog.bielu.com/2008/12/null-object-design-pattern.html">here</a>. I hope my comment link will work as intended...
Hypercube
Using interface instead of extending another class is always cleaner so if you can choose, choose the interface. The concerns against null object pattern usually are related to the fact that you can't just drop it into existing code; you have to design rest of the code to work with NO:s too.
Esko
If i add a static method called getEmptyObject, who simply returns a new Object of my kind, wouldn't be enough? The default (null values) initializing will be done in the constructor.
Hypercube
+2  A: 

If an error occurs, thow an exception. If there's no data, return an empty collection, not a null. (Also, generally you should return the more generic 'Map', not the specific implementation),

Nerdfest
Good one. I missed the return of the explicit type. +1.
CPerkins
A: 

You can significantly reduce the amount of boilerplate JDBC code by using Spring-JDBC instead of plain-old JDBC. Here's the same method rewritten using Spring-JDBC

public static Hashtable<Long, Dogs> getSomeDogs(String colName, String colValue) {

    StringBuffer sql = new StringBuffer();
    sql.append("SELECT * FROM ").append("dogs_table");
    sql.append(" WHERE ").append(colName).append("='");
    sql.append(colValue).append("'");

    Hashtable<Long, Dogs> result = new Hashtable<Long, Dogs>();

    RowMapper mapper = new RowMapper() {

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Dogs dog = new Dogs();
            //...initialize the dog from the current resultSet row
            result.put(new Long(dog.getId()), dog);
        }
    };
    (Hashtable<Long, Dogs>) jdbcTemplate.queryForObject(sql, mapper);
}

Spring takes care of:

  1. Iterating over the ResultSet
  2. Closing the ResultSet
  3. Handling exceptions consistently

As others have mentioned you really should use a PreparedStatement to construct the SQL instead of a String (or StringBuffer). If for some reason you can't do this, you could improve the readability of the query by constructing the SQL like this instead:

    String sql = 
        "SELECT * FROM dogs_table " +
        "WHERE " + "colName" + " = '" + colValue + "'";
Don
As this may seem more readable, if using the "manual" query builder, as in my example, i've founded that it is NOT. Using .append() method of the "deprecated" StringBuilder, separates in more distinctive tokens the query to build. All this make little sense now, comparing to people suggestions to ALWAYS change the current style, according to their own. Or the recommended one. However, one developper cannot adopt X styles, for X different answerers. For instance, the checked or unchecked use of exceptions question has NO answer so far..and so on...
Hypercube
Some are even more disturbed of the format of the question, rather than the essence of that question. I did my best to make it look good, this is how it went into the wild. I've asked 4 distinct questions, i got some vague answers..i am sorry, but beside the use of new java types like StringBuilder or HashMap, i cannot extract anything of use from the answers so far :-(. Yes, perhaps SpringJDBC is a great framework, but i didn't ask for it. It's just another dependency to my project..and i am not sure i wanna commit to that yet.
Hypercube
About the SpringJDBC advantages : 1. I am not annoyed by iterating the result set myself; 2. I have a static method for closing the resultSet safely; 3.I already use apache.commons.lang for dealing with exceptions, like getting the rootStackTrace() instead of some nasty-nested stacktraces, so..what advantages are left?
Hypercube
+3  A: 

You ask five questions

1. What ways do u suggest on improving this technique of returning some dogs, with some attribute?

Several, actually.

  • Your method is static - this isn't terrible, but leads to you using another static "executeQuery", which smells of Singleton to me...
  • The class "Dogs" violates an OO naming practice - plural nouns don't make good class names unless one instance of the class holds a collection of things - and it appears that Dogs is actually "Dog".
  • HashTable is all but deprecated. HashMap or ConcurrentHashMap give better performance.
  • I can't see a reason to create the first part of your query with multiple appends - it's not bad, but it's less readable than it might be, so sql.append ("SELECT * FROM dogs_table WHERE "); makes a more sensible beginning if you're just going to hardcode the selected columns (*) and table name (dogs_table) anyway.

2. rs.next() will return false for a null ResultSet, or will generate an exception

This doesn't seem to be a question, but yes, rs.next() returns false as soon as there's no longer any rows to process.

3. What if, while initializing a dog object from the current row of the ResultSet, something bad happens

If "something bad happens", what you do next is up to you and your design. There's the forgiving approach (return all the rows you can), and the unforgiving (throw an exception). I tend to lean towards the "unforgiving" approach, since with the "forgiving" approach, users won't know that you haven't returned all the rows that exist - just all the ones you'd gotten before the error. But there might be cases for the forgiving approach.

4. I think u will all agree on this one : nothing bad happens, there are no rows on the interrogation, a null value will be return.

This isn't something on which there's an obvious right answer. First, it's not what's happening in the method as written. It's going to return an empty HashTable (this is what was meant by a "null object"). Second, null isn't always the answer in the "no results found" case.

I've seen null, but I've also seen an empty result variable instead. I claim they're both correct approaches, but I prefer the empty result variable. However, it's always best to be consistent, so pick a method of returning "no results" and stick with it.

5. I've noticed people and groups of people saying that one should split the application into layers, or levels of some kind.

This is harder to answer than the others, without seeing the rest of your application.

CPerkins
Thank u for the contextual and concise answer. You were wright. 5 question (i was thinking of 4, but i've actually added another one :-) ). I am using a singletone manager for database access (is that bad?). If the suggested types performs better, i shall adopt them. It might sound stupid, but i wasnt aware of some things here..if i were, i wouldn't ask for info. Thanks again. I will use : HashMap, StringBuilder(where the case), PreparedStatement instead of executing strings, NullObjects instead of null value and Dog instead of Dogs. That's valuable info.
Hypercube
Update.I've checked the objects in my project, related to db, and they are all named "Dog instead of Dogs". The truth is i was a bit unaware of the convention, but somehow it seemed more appropriate.Another light in the darkness :-).
Hypercube
You're welcome. Yes, the Singleton pattern is ... well, I won't say *bad*, but it's a questionable practice. Anytime I see one in a design, it causes me to wonder if it's really needed. Google around for it, and you'll see what I mean.
CPerkins
I wonder why should i use HashMap an all cases. I've performed a search on the matter of HashMap vs. Hashtable, and i tend to stick with Hashtable. On some cases HashMap tends to be about 5% faster than Hashtable (sacrificing thread-safe prop of your collection), but syncronized HashMap IS slower than the "old" hashtable. So..why should i use HashMap again?
Hypercube
Hypercube
s/decremented/deprecated =)
gnud
I've also noticed that..:-D
Hypercube
@gnud: ouch. thanks. I'll edit for posterity's sake, but thanks for the edit.
CPerkins
@Hypercube - actually, HashTable doesn't provide thread-safety, at least not complete safety. There are many compound actions (like insert-if-absent) which would have to be externally synchronized. Also, iteration isn't thread-safe: HashTable's iterator isn't fail-fast, so if one thread holds an iterator, and another changes the map, you can get inconsistent results, while with a HashMap, you get a ConcurrentModificationException. But this has gotten pretty specific. There's some good threads on this topic in the SO archives.
CPerkins
Thank u for your patience with a stubborn donkey :-). I'll give it some more thought then.
Hypercube
+2  A: 

Do not build SQL queries by concatenating strings, like you're doing:

sql = new StringBuffer();
sql.append("SELECT * FROM ").append("dogs_table");
sql.append(" WHERE ").append(colName).append("='");
sql.append(colValue).append("'");

This makes your code vulnerable to a well-known security attack, SQL injection. Instead of doing this, use a PreparedStatement and set the parameters by calling the appropriate set...() methods on it. Note, you can only use this to set column values, you can't use this to dynamically construct a column name, as you're doing. Example:

PreparedStatement ps = connection.prepareStatement("SELECT * FROM dogs_table WHERE MYCOL=?");
ps.setString(1, colValue);

rs = ps.executeQuery();

If you use a PreparedStatement, the JDBC driver will automatically take care of escaping certain characters that might be present in colValue, so that SQL injection attacks don't work anymore.

Jesper
Well spoken. Thank u. After seeing the reason for the change, the change will follow.
Hypercube