Avoid Map and String in your class interfaces
Looking back at the APIs I’ve created, I realize one of my biggest mistakes was using classes from the standard SDK in their interfaces. Using classes like java.lang.String and java.util.Map was, of course, down to my laziness about introducing dedicated types to represent the entity in question. I paid dearly for that laziness later.
Using a Map
A Map seemed convenient for representing a row returned by a remote API.
public void processRow(java.util.Map row) {
...
}It looked simple at first, but after a few weeks of building objects around that row representation, I needed the row to tell me more about itself. I needed metadata for each column. Worse, I needed to check whether a row was original or generated synthetically. Now I had a problem. You can’t just add a method to Map. I had to go to the trouble of passing the metadata another way. For the row type, I tested for a special Map implementation I had to create. Lesson for next time: if you have java.util.Map in your API, something is probably wrong. Respect to the exceptions that prove the rule.
Using a String
I had a class that represented the context of the currently logged-in user. The user identifier was a plain java.lang.String, even though it was a numeric identifier. Another mistake I ought to rap my knuckles for.
public String getUserId() {
...
}As luck would have it, the original representation did change from a number to a string. The dependent APIs all used String, and wherever we had to distinguish the old number from the new string, we had to parse it apart. The right solution would have been to use an object representing the user identifier from the outset.
public UserIdentifier getUserId() {
...
}Another common misuse of java.lang.String comes in the form of constants that could be expressed with an enum. By the way, I recommend Stefan Schmidt’s rather controversial but instructive article Never, never, never use String in Java (or at least less often :-).
These types cause the same problem in return values. Sometimes we even reach for an array or introduce some sort of tuple. Avoid that too. It ties your hands later, makes the API harder to understand, and makes it difficult to extend while preserving backward compatibility.
Related articles
Related CZ Podcast episodes
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio