Java is one of the most popular languages out there for back-end programming. It has many advantages that made it so popular. I am not going to discuss that here.
But Java is old, and keeps compatibility between versions. Some things could have been implemented in a different way, in retrospective.
In this post I want to focus on some syntactic constructs that should be avoided or reconsidered.
- null - I did not invented it of course, but although it is there it should be avoided.
Even the inventor said that. What can we use instead? in many cases we are using null when we don't have a value or "answer" to give the client back. Such examples are: return from method, or default behavior in switch statements.
In many cases it is better to just throw a RuntimeException or IllegalArgumentException to indicate such state. Another way to workaround that is to use Guava's Optional. When returning that from a method, it indicates very clearly that the user of that method should be aware an empty value is possible.
- Checked exception - First a short reminder: Checked exceptions are exception that when thrown must be declared in the method signature and handled explicitly by the client.
In Java all exceptions are checked except RuntimeException and Error (and its predecessors). In that case, it is really a matter of taste but here is what I think about using checked exceptions.
In first glimpse checked exception sounds like a novel idea, similar to the optional above. Implementer can declare in the method signature about errors to allow the client handle them. But it has few major drawbacks that leave them unusable:
- Checked exceptions are like implementation details that are thrown into the method signature, so for example if your method used files to retrieve a value it will throw IOException. then later the implementer decided to use database, he will throw a JdbcException so the user of the method has to modify the usage because of a change in internal details.
- Many time - the best place to handle the exception is not directly at the usage of a method but in another, more general place when you can get a valid state to recover from that error. that cause all the methods on the way to get polluted with the exception signature as well. just another details that will make refactor harder.
- Anyway, a user of a method has to handle runtime exceptions.
- I saw many cases that it ended up with just throwing the general not-saying-anything Exception. This is like saying that an error might occurred. Ha!
- Well, no other language used it after Java AFAIK. That is a sign, isn't it?!
- Language feature such as generics and lambda - In this case I just suggest to be cautious. I have seen far too many cases that a new feature comes to Java, and developers (like myself) just start using it all over the code, make the code unreadable. So when using a new feature, like driving a car, start with a low gear.
- Un-popular or un-maintained frameworks - Java SDK comes with a lot of goodies, But they do mistakes there also.
Java logging for example, was introduced when log4j was already popular. However, java logging gave a poor api compare to log4j or slf4j. The main advantage of it is you don't have to depend on a third-party library, but you pay for that in convinience.
A different example is the apache-commons. It was a good library with many features, but it is so ancient and unmaintained that it even doesn't support Java 5 generics well. In most cases I prefer other alternatives such as Google's guava.
That's all for now. LMK what you think.