After coding for a while (eek, almost 20 years or so in my case, time flies when you’re having fun), one starts to embrace those habits. Because, you know…
This is why people embrace “defensive programming”, i.e. paranoid habits that sometimes make total sense, and sometimes are rather obscure and/or clever and perhaps a bit eerie when you think of the person who wrote it. Here’s my personal list of top 10 useful, yet paranoid Java programming techniques. Let’s go:
1. Put the String literal first
It’s just never a bad idea to prevent the occasional NullPointerException by putting the String literal on the left side of an equals() comparison as such:
// Bad
if (variable.equals("literal")) { ... }
// Good
if ("literal".equals(variable)) { ... }
This is a no-brainer. Nothing is lost from rephrasing the expression from the less good version to the better one. If only we had true Options though, right? Different discussion…
2. Don’t trust the early JDK APIs
In the early days of Java, programming must’ve been a big pain. The APIs were still very immature and you might’ve walked across a piece of code like this:
String[] files = file.list();
// Watch out
if (files != null) {
for (int i = 0; i < files.length; i++) {
...
}
}
If this abstract pathname does not denote a directory, then this method returns null. Otherwise an array of strings is returned, one for each file or directory in the directory.
Yeah right. Better add another check, though, just to be sure:
if (file.isDirectory()) {
String[] files = file.list();
// Watch out
if (files != null) {
for (int i = 0; i < files.length; i++) {
...
}
}
}
This is paranoid, I know. The Javadoc of String.indexOf() clearly states that…
the index of the first occurrence of the character in the character sequence represented by this object [is returned], or -1 if the character does not occur.
So, -1 can be taken for granted, right? I say nay. Consider this:
// Bad
if (string.indexOf(character) != -1) { ... }
// Good
if (string.indexOf(character) >= 0) { ... }
Who knows. Perhaps they’ll need ANOTHER encoding at some point in time to say, the otherString would have been contained if checked case-insensitively… Perhaps a good case for returning -2? Who knows.
After all, we’ve had billions of discussions about the billion dollar mistake, which is NULL. Why shouldn’t we start discussions about -1, which is – in a way – an alternative null for primitive type int?
4. Avoid the accidental assignment
Yep. It happens to the best (although, not to me. See #7).
(Assume this is JavaScript, but let’s be paranoid about the language as well)
// Ooops
if (variable = 5) { ... }
// Better (because causes an error)
if (5 = variable) { ... }
// Intent (remember. Paranoid JavaScript: ===)
if (5 === variable) { ... }
Again. If you have a literal in your expression, put it to the left side. You can’t accidentally go wrong here, when you meant to add another = sign.
5. Check for null AND length
Whenever you have a collection, array, etc., make sure it’s present AND not empty.
// Bad
if (array.length > 0) { ... }
// Good
if (array != null && array.length > 0) { ... }
You never know where those arrays come from. Perhaps from early JDK API?
6. All methods are final
You can tell me all you want about your open/closed principles, that’s all bollocks. I don’t trust you (to correctly extend my classes) and I don’t trust myself (to not accidentally extend my classes). Which is why everything that is not explicitly intended for subtyping (i.e. only interfaces) is strictly final. See also item #9 of our 10 Subtle Best Practices when Coding Java list.
// Bad
public void boom() { ... }
// Good. Don't touch.
public final void dontTouch() { ... }
Yes. It’s final. If that doesn’t work for you, patch it, or instrument it, or rewrite the byte code. Or send a feature request. I’m sure that your intent of overriding the above isn’t a good idea anyway.
7. All variables and parameters are final
As I said. I don’t trust myself (to not accidentally overwrite my values). Having said so, I don’t trust myself at all. Because…
… which is why all variables and parameters are made final, too.
// Bad
void input(String importantMessage) {
String answer = "...";
answer = importantMessage = "LOL accident";
}
// Good
final void input(final String importantMessage) {
final String answer = "...";
}
OK, I admit. This one, I don’t apply very often, really, although I should. I wish Java got it right like Scala, where people just type val all over the place, without even thinking about mutability – except when they need it explicitly (rarely!), via var.
8. Don’t trust generics when overloading
Yes. It can happen. You believe you wrote that super nice API which totally rocks and is totally intuitive, and along comes some user who just raw-casts everything up to Object until the darn compiler stops bitching, and suddently they’ll link the wrong method, thinking it’s your fault (it always is).
Consider this:
// Bad
<T> void bad(T value) {
bad(Collections.singletonList(value));
}
<T> void bad(List<T> values) {
...
}
// Good
final <T> void good(final T value) {
if (value instanceof List)
good((List<?>) value);
else
good(Collections.singletonList(value));
}
final <T> void good(final List<T> values) {
...
}
Because, you know… Your users, they’re like
// This library sucks
@SuppressWarnings("all")
Object t = (Object) (List) Arrays.asList("abc");
bad(t);
Trust me. I’ve seen everything. Including things like
It’s good to be paranoid.
9. Always throw on switch default
Switch… One of those funny statements where I don’t know whether to petrify with awe or to just cry. Anyway, we’re stuck with switch, so we may as well get it right when we have to. I.e.
// Bad
switch (value) {
case 1: foo(); break;
case 2: bar(); break;
}
// Good
switch (value) {
case 1: foo(); break;
case 2: bar(); break;
default:
throw new ThreadDeath("That'll teach them");
}
Because that moment where value == 3 is introduced into the software, it’ll come for sure! And don’t say enum, because it’ll happen to enums as well!
10. Switch with curly braces
In fact, switch is the most wicked statement anyone has every allowed to get into a language while they were either drunk or lost a bet. Consider the following example:
// Bad, doesn't compile
switch (value) {
case 1: int j = 1; break;
case 2: int j = 2; break;
}
// Good
switch (value) {
case 1: {
final int j = 1;
break;
}
case 2: {
final int j = 2;
break;
}
// Remember:
default:
throw new ThreadDeath("That'll teach them");
}
Within the switch statement, there is only one scope defined among all the case statements. In fact, these case statements aren’t even really statements, they’re like labels and the switch is a goto call. In fact, you could even compare case statements with the astonishing FORTRAN 77 ENTRY statement, a device whose mystery is only exceeded by its power.
This means that the variable final int j is defined for all the different cases, regardless if we issue a break or not. Not very intuitive. Which is why it’s always a good idea to create a new, nested scope per case statement via a simple block. (but don’t forget the break within the block!)
Conclusion
Paranoid programming may seem weird at times, as code often turns out to be a bit more verbose than really needed. You might think, “oh this is never gonna happen”, but as I said. After 20 years or so programming, you just don’t want to fix those stupid little unnecessary bugs anymore that exist only because the language is so old and flawed. Because you know…
Now, it’s your turn!
What’s your most paranoid quirk in programming?
Read on
Did you enjoy this list? Have more spare time to waste on lists? We have more. Here are:
4. is completely wrong.
if (variable =4) doesn’t compile at all.
This habit comes from C/C++ where condition have not the boolean type.
This ‘Yoda condition’ has then no reason to be used in Java.
Interesting, care to explain? Or link to an explanation?
The following will not compile – 5 is not boolean
You’re late (but right), that has already been fixed :-)
The ‘switch’ problems – static analysis will help with these.
Well, to be fair, static analysis is an inevitable consequence of paranoia as exposed in this article. Yet, I have yet to find a tool that doesn’t piss me off by being overly strict…
If the string is on the left, the compiler knows the class at compile time and can optimize away the method lookup. If the object is on the left, it could be any arbitrary class and the .equals method has to be dynamically found at runtime.
Well – when the object you call the method upon is constant that virtual method call can be devirtualized and actually called in a static way since the compiler and runtime can prove that only a particular method is called. This is especially true for java.lang classes – some are final, they are also loaded by a special class loader and such calls are easily provable to be monomorphic rather than polymorphic.
In the particular case with a String literal using the String.equals() method – this can be actually an intrinsic method, see here:
// Bad
switch (options) {
case FOO: foo(); break;
case BAR: bar(); break;
default:
throw new ThreadDeath("That'll teach them");
}
// Good
if (options != null) {
switch (options) {
case FOO: foo(); break;
case BAR: bar(); break;
default:
throw new ThreadDeath("That'll teach them");
}
} else {
throw new ThreadDeath("That'll teach them");
}
First, brackets surround all conditional content — too often people create a one-liner and then debugging or something else is thrown in, but they didn’t have brackets because they originally were thinking “I’m just going to do this one thing” and someone forgot to add brackets. Another scenario is the confusion that nested conditionals can cause if you don’t use brackets.
I do not allow auto-(un)boxing — all boxing and unboxing must be explicit or our compilers error out. Why? Because it’s all too common that people pick the wrong thing between parse* and valueOf -or- someone will accidentally do Boolean bool=true; Will auto-(un)boxing break your code? No, but I’ve found that most of the time, people didn’t really mean to switch between a primitive and Object — it was accidental and a huge waste.
For example, we have a ValidationUtils class that validates (using whitelists for most things) data, but it also contains two isEmpty methods (one for Object and another for Object…). Everyone uses this, rather than checking for null and then doing isEmpty, length()==0, size==0, etc, because this ensures that null is checked and then it uses reflection to search for the aforementioned methods. Sometimes someone accidentally sends a primitive to it:
public void gatewayMethod(final boolean isGreat, final int place,@NotNull final SomeObject obj) {
if (ValidationUtils.isEmpty(isGreat)) {
throw new IllegalParameter("The parameter isGreat is empty!");
}
if (ValidationUtils.isEmpty(obj)) {
throw new IllegalParameter("The parameter obj is empty!");
}
workerMethod(isGreat,place,obj);
}
The last thing is not only checking if an array or data structure is null/empty, but checking each item before using it. Arrays and most data structures allow nulls, so always check for them when working with array/data structure content (especially if the data is coming from an external source like another module, an API, a database, etc).
String[] strings = new String[]{"blah",null,"2"};
if (!ValidationUtils.isEmpty(strings)) {
for (String string:strings) {
if (ValidationUtils.isEmpty(string)) {
// Do something
}
}
}
First, brackets surround all conditional content — too often people create a one-liner and then debugging or something else is thrown in […]
Hmm, very interesting. I’ve noticed this as well, especially when working with Java 8 Streams. The functional style is hard enough to debug already, but the one-liners make tooling really useless… Would you mind showing an example in code of how you use those brackets?
I do not allow auto-(un)boxing — all boxing and unboxing must be explicit or our compilers error out.
over all of the above. It’s as (or more!) null-safe. It’s also more readable. Yes, it’s a bit more syntactic sugar, although that can be reduced with a static import. Whereas:
if ("literal".equals(variable))...
has that “throw momma from the train a kiss” feel. It’s harder to READ. Nobody actually thinks that way. (Well, unless you’re a Reversed Pole. :-) )
In fact, many of the null-safe points you make are best addressed with various (apache commons, google, whatever) packages that do the work for you, and at a better level of abstraction, to boot.
Actually there is also good practice to use contracts in your code. There is nice class in Guava – Preconditions, so you can guard against wrong input like this:
Oh god, Lukas, your habit of final-ing and visibility hiding everything was a huge pain actually when I wanted to extend the jOOQ generated DAOs (EVERYTHING final). I had to to copy and paste your code and now my DAOs all have to have to contain this:
private interface IDao extends DAO {}
@Delegate(excludes=IDao.class)
private final jooqdemo.data.tables.daos.ArtikelDao delegate
And believe me, you did not know better then me how to to implement update / insert properly.
NullPointerException right there! Should be “files != null”.
Oh my o_O Thank you very much. Fixed! :)
4. is completely wrong.
if (variable =4) doesn’t compile at all.
This habit comes from C/C++ where condition have not the boolean type.
This ‘Yoda condition’ has then no reason to be used in Java.
Hah, damnit. Been doing too much JavaScript lately. But for the sake of argument: Let’s be paranoid about the language that we’re currently using!
Actually, there’s a reason:
Well, those folks that compare for
true
orfalse
inif
statements deserve a slapping anyway…;-)
This
will be optimized much better than
So it is not only NullPointerExceptions
————-
The following will not compile – 5 is not boolean
you will have to rewrite it with boolean variable and a boolean value (true, false)
You can try to bit more inventive with autoboxing:
————-
The ‘switch’ problems – static analysis will help with these.
Interesting, care to explain? Or link to an explanation?
You’re late (but right), that has already been fixed :-)
Well, to be fair, static analysis is an inevitable consequence of paranoia as exposed in this article. Yet, I have yet to find a tool that doesn’t piss me off by being overly strict…
If the string is on the left, the compiler knows the class at compile time and can optimize away the method lookup. If the object is on the left, it could be any arbitrary class and the .equals method has to be dynamically found at runtime.
JIT (probably) does that at runtime. Besides, make a little experiment:
Java
bytecode
I’d say the compiler compiles exactly equivalent code, right?
Well – when the object you call the method upon is constant that virtual method call can be devirtualized and actually called in a static way since the compiler and runtime can prove that only a particular method is called. This is especially true for java.lang classes – some are final, they are also loaded by a special class loader and such calls are easily provable to be monomorphic rather than polymorphic.
In the particular case with a String literal using the String.equals() method – this can be actually an intrinsic method, see here:
https://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/classfile/vmSymbols.hpp#l763
Interesting. I’ve tried (https://blog.jooq.org/2015/08/11/top-10-useful-yet-paranoid-java-programming-techniques/#comment-133399), but it doesn’t seem to do it. Does that perhaps only apply to corner cases?
Also, I wonder if the compiler should even worry about these things, given that JIT already works miracles… the “intrinsic method” specification is part of the VM, not the compiler, or am I wrong?
Speaking of enum switches, here is 9b:
Ooooh, this hits me every time! NIce catch!
First, brackets surround all conditional content — too often people create a one-liner and then debugging or something else is thrown in, but they didn’t have brackets because they originally were thinking “I’m just going to do this one thing” and someone forgot to add brackets. Another scenario is the confusion that nested conditionals can cause if you don’t use brackets.
I do not allow auto-(un)boxing — all boxing and unboxing must be explicit or our compilers error out. Why? Because it’s all too common that people pick the wrong thing between parse* and valueOf -or- someone will accidentally do Boolean bool=true; Will auto-(un)boxing break your code? No, but I’ve found that most of the time, people didn’t really mean to switch between a primitive and Object — it was accidental and a huge waste.
For example, we have a ValidationUtils class that validates (using whitelists for most things) data, but it also contains two isEmpty methods (one for Object and another for Object…). Everyone uses this, rather than checking for null and then doing isEmpty, length()==0, size==0, etc, because this ensures that null is checked and then it uses reflection to search for the aforementioned methods. Sometimes someone accidentally sends a primitive to it:
The last thing is not only checking if an array or data structure is null/empty, but checking each item before using it. Arrays and most data structures allow nulls, so always check for them when working with array/data structure content (especially if the data is coming from an external source like another module, an API, a database, etc).
Hmm, very interesting. I’ve noticed this as well, especially when working with Java 8 Streams. The functional style is hard enough to debug already, but the one-liners make tooling really useless… Would you mind showing an example in code of how you use those brackets?
Good points! And also the risk of running into a subtle
NullPointerException
is mitigated when doing things explicitly, see also https://blog.jooq.org/2013/10/08/java-auto-unboxing-gotcha-beware.Hi again, Lukas:
Small note… I prefer
over all of the above. It’s as (or more!) null-safe. It’s also more readable. Yes, it’s a bit more syntactic sugar, although that can be reduced with a static import. Whereas:
has that “throw momma from the train a kiss” feel. It’s harder to READ. Nobody actually thinks that way. (Well, unless you’re a Reversed Pole. :-) )
In fact, many of the null-safe points you make are best addressed with various (apache commons, google, whatever) packages that do the work for you, and at a better level of abstraction, to boot.
From a paranoid perspective: WHAT IF THE LIBRARY CANNOT BE FOUND AT RUNTIME!?!? ;-)
Anyway,
StringUtils.equals()
I prefer as well, or perhapsObjects.equals(...)
.Unfortunately, no – static-import you cannot any
equals()
method. See https://blog.jooq.org/2015/02/18/thou-shalt-not-name-thy-method-equals.As a German speaker, no problem I have inversing sentence structures. This helps, I hope.
Hah! Good reminder (about the static import).
“Yoda” should we be calling you. Reversed sentences you prefer.
Actually there is also good practice to use contracts in your code. There is nice class in Guava – Preconditions, so you can guard against wrong input like this:
It will fail and fire an exception if incorrect input is provided.
Also, it’s easy to test it
True. But that’s a lot of logic for only little effect. If things could only be done with types… :)
Yeah, haskell-like algebraic types could help. But we’re living in Java World, aren’t we?
We are indeed. Let’s add some annotations to our types to implement those checks ;)
@NotNull annotation doesn’t work in runtime i’ts compile time only annotation.
Just like types, right? :) You could obviously add some additional instrumentation…
Oh god, Lukas, your habit of final-ing and visibility hiding everything was a huge pain actually when I wanted to extend the jOOQ generated DAOs (EVERYTHING final). I had to to copy and paste your code and now my DAOs all have to have to contain this:
And believe me, you did not know better then me how to to implement update / insert properly.
Well, you could’ve discussed the issue on the user group and helped us all improve :)
What was the exact problem? Or asked differently: What kind of feature are you missing?