Code Time with Cody

$ dd if=/usr/cody of=www

Why My Variables Are Final

By day, I write Java code in the enterprise world. When I compare my code to others’ code, I sometimes feel like I excessively use the final keyword. It seems that most developers will only use final for a constant declaration such as

1
private static final String MIME_TYPE_JSON = "application/json";

However, I would bet that 95% of my my local variables are declared final. Am I going overboard?

Saving another developer (or future you) some thinking

Consider a typical line of code that does not use final:

1
path = path.replace('\\', '/');

There are a few reasons this makes me cringe:

  • This forces someone reading your code to perform a mental shift. This developer has grown to know and love path, and now it isn’t what it used to be. Humans aren’t nearly as good at context shifting as we think we might be. Sure, in this trivial example, the harm seems minimal, but the more shifting references in the code, the harder it is to keep track of what is what.
  • Being more explicit would make your code easier to understand. Why not give other developers a better clue as to what’s going on?
1
final String unixStylePath = path.replace('\\', '/');

Encouraging best practices

You’ll find that if you consistently use final variables, the compiler will prevent you from shooting yourself in the foot from a maintainability perspective.

Scoping

Using final will encourage you to use the narrowest scoping possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
String name;
Address address;
String city;
int age;
for(User user : users) {
  name = user.getName();
  address = user.getAddress();
  if (null != address) {
      city = address.getCity();    
  }
  age = user.getAge();
  userRegistry.add(name, city, age);
}

What’s wrong with that code? Okay, you probably realized that if the address is null we will register the user with the city of a previous user in the list. However, in order to realize this, you had to think and scrutinize the code at least a little bit. If you were in the habit of using final variables, things would look more like this:

1
2
3
4
5
6
7
8
9
10
11
12
for (final User user : users) {
  final String name = user.getName();
  final Address address = user.getAddress();
  final String city;
  if (null == address) {
      city = null;
  } else {
      city = address.getCity();
  }
  final int age = user.getAge();
  userRegistry.add(name, city, age);
}

The version using final won’t let you get away with letting a value persist across iterations. It also won’t leave any broadly-scoped variables hanging around once your code is done with the loop. In my opinion, it is also easier to digest. You immediately see what the value of each variable is, and because you know the reference won’t change, you don’t have to think much at all about what is happening.

Complicated logic trees

If your someone else’s code has some complicated logic tree with if, else if, and else branches of various levels, it can be tough to track down blocks that might execute twice and thus reassign a variable. If those variables are declared final, the compiler will make sure that these variables don’t get assigned twice. Here is where you might say

But sometimes I know two blocks are mutually exclusive but the compiler can’t tell.

This could definitely be the case; I won’t say you are wrong. But I will ask a couple questions:

  • Does everyone else who will ever see this code know this same magical fact that you do? Maybe others aren’t nearly as smart as you are and would benefit from you making the mutual-exclusivity explicit.
  • Can you restructure your logic so that the compiler knows that only one of these blocks can execute? This will make your code much less error prone.

Free minor optimizations

The compiler and JVM can make minor optimizations on final variables. Sure these are small gains, but I’ll take them since they come free with the other benefits of using final.

Closing thoughts

As you most likely know if you have up to this point, final has more than one meaning in Java. I think that most Java developers can understand use cases for final classes, methods, and fields, even if they don’t use them regularly. However, I think they belittle the utility of final local variables. Several developers have told me

Sure, I should probably make more of my variables final, but it isn’t worth the verbosity.

I agree that the verbosity is a shame. I think that in Java variables should be final unless declared otherwise (have I mentioned that Scala is my hobby language?). We are stuck with final being opt-in instead of opt-out, so here are my closing points to ponder:

  • Are you concerned about typing the extra 6 characters (including space) for your variables?
    • Which is going to end up taking more time, typing the extra characters or debugging problems stemming from broadly-scoped variables or inadvertent reasssignments?
  • Are you concerned about extra noise in your code that distracts from the real logic?
    • This is a valid concern. But I think that the extra verbosity helps by saying “Look, I am a simple assignment. You don’t have to worry about me changing down the line. You can focus on more complicated things.”

Comments