Guard Clause
While programs have a main flow, some situations require deviations from the main flow. The guard clause is a way to express simple and local exceptional situations with purely local consequences. Compare the following:
void initialize() { if (!isInitialized()) { ... } }
with:
void initialize() { if (isInitialized()) return; ... }
When I read the first version, I make a note to look for an else clause while I am reading the then clause. I mentally put the condition on a stack. All of this is a distraction while I am reading the body of the then clause. The first two lines of the second version simply give me a fact to note: the receiver hasn’t been initialized.
If-then-else expresses alternative, equally important control flows. A guard clause is appropriate for expressing a different situation, one in which one of the control flows is more important than the other. In the initialization example above, the important control flow is what happens when the object is initialized. Other than that, there is just a simple fact to notice, that even if an object is asked to initialize multiple times it will only execute the initialization code once.
Back in the old days of programming, a commandment was issued: each routine shall have a single entry and a single exit. This was to prevent the confusion possible when jumping into and out of many locations in the same routine. It made good sense when applied to FORTRAN or assembly language programs written with lots of global data where even understanding which statements were executed was hard work. In Java, with small methods and mostly local data, it is needlessly conservative. However, this bit of programming folklore, thoughtlessly obeyed, prevents the use of guard clauses.
Guard clauses are particularly useful when there are multiple conditions:
void compute() { Server server= getServer(); if (server != null) { Client client= server.getClient(); if (client != null) { Request current= client.getRequest(); if (current != null) processRequest(current); } } }
Nested conditionals breed defects. The guard clause version of the same code notes the prerequisites to processing a request without complex control structures:
void compute() { Server server= getServer(); if (server == null) return; Client client= server.getClient(); if (client == null) return; Request current= client.getRequest(); if (current == null) return; processRequest(current); }
A variant of guard clause is the continue statement used in a loop. It says, “Never mind this element. Go on to the next one.”
while (line = reader.readline()) { if (line.startsWith('#') || line.isEmpty()) continue; // Normal processing here }
Again, the intent is to point out the (strictly local) difference between normal and exceptional processing.