Top 10 Useful, Yet Paranoid Java Programming Techniques


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…

Anything that Can Possibly Go Wrong, Does.

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++) {
        ...
    }
}

Looking paranoid? Perhaps, but read the Javadoc:

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++) {
            ...
        }
    }
}

Bummer! Violation of rule #5 and #6 of our 10 Subtle Best Practices when Coding Java list. So be prepared and add that null check!

3. Don’t trust that “-1”

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…

yesterdays-regex

… 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

7H6FAH7[1]

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:

And last but not least, because we’re paranoid…

27 thoughts on “Top 10 Useful, Yet Paranoid Java Programming Techniques

  1. 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.

  2. This

    if ("literal".equals(variable)) { ... }
    // or any FIXED_OBJECT.VIRTUAL_METHOD(CNANGING_OBJECT)
    

    will be optimized much better than

    if (variable.equals("literal")) { ... }
    // or any CNANGING_OBJECT.VIRTUAL_METHOD(FIXED_OBJECT)
    

    So it is not only NullPointerExceptions

    ————-
    The following will not compile – 5 is not boolean

    // Ooops
    if (variable = 5) { ... } 
    

    you will have to rewrite it with boolean variable and a boolean value (true, false)

    if (variable = true) { ... } 
    

    You can try to bit more inventive with autoboxing:

    Boolean variable = false;
    if (variable = null){
    }
    

    ————-
    The ‘switch’ problems – static analysis will help with these.

    • This … will be optimised much better than …

      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.

        • JIT (probably) does that at runtime. Besides, make a little experiment:

          Java

          public static void main(String[] args) {
              if ("a".equals(args[0]))
                  System.out.println("a");
          
              if (args[0].equals("b"))
                  System.out.println("b");
          }
          

          bytecode

               0  ldc  [16]
               2  aload_0 [args]
               3  iconst_0
               4  aaload
               5  invokevirtual java.lang.String.equals(java.lang.Object) : boolean [18]
               8  ifeq 19
              11  getstatic java.lang.System.out : java.io.PrintStream [24]
              14  ldc  [16]
              16  invokevirtual java.io.PrintStream.println(java.lang.String) : void [30]
              19  aload_0 [args]
              20  iconst_0
              21  aaload
              22  ldc  [36]
              24  invokevirtual java.lang.String.equals(java.lang.Object) : boolean [18]
              27  ifeq 38
              30  getstatic java.lang.System.out : java.io.PrintStream [24]
              33  ldc  [36]
              35  invokevirtual java.io.PrintStream.println(java.lang.String) : void [30]
              38  return
          

          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:

      http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/classfile/vmSymbols.hpp#l763

  3. Speaking of enum switches, here is 9b:

    
    // 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");
    }
    
  4. 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.

      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.

  5. Hi again, Lukas:

    Small note… I prefer

    if (StringUtils.equals (variable, "literal")) ...
    

    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.

  6. 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:

    void foo(List someList, MyObject obj) {
         Preconditions.checkNotNull(someList);
         Preconditions.checkNotNull(obj);
         Preconditions.checkArgument(!someList.isEmpty());
    
      // ...
    
    }
    

    It will fail and fire an exception if incorrect input is provided.

    Also, it’s easy to test it

    @Test(expected=NullPointerException.class)
    public void shouldNotAcceptNull() {
       foo(null, null);
    }
    
  7. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s