The Java Empty Statement

Marcio Endo
April 23, 2023

Welcome to Objectos Weekly issue #023.

The Java language has a statement that does nothing. It is aptly named "The Empty Statement". The following Java code compiles without errors:

final void example() {
  while (shouldLoop());

  ;

  if (test()); else;
    
  {;;; {;}}
}

In this issue we will look at Java's empty statement.

Let's begin.

The Empty Statement

The Empty Statement is defined in Section 14.6 of the Java Language Specification (JLS).

It is a short section so we can quote it in its entirety:

An empty statement does nothing.

EmptyStatement:
  ;

Execution of an empty statement always completes normally.

Next, let's create some examples to see the empty statement "in action". In other words, let's see the empty statement doing nothing.

Statements with substatements

The if, while, for and do statements contain other statements. So let's use the empty statement with them.

We will start with the while statement. The following compiles without errors:

final void whileInfinity() {
  while (true);
}

Though I wouldn't recommend running it.

We can also use it with the for statement. The following also compiles without errors:

final void forExample(int times) {
  for (int i = 0; i < times; i++);
}

Perhaps you can use it if you want to burn a few CPU cycles.

Next, let's use the empty statement with the if statement. The following compiles without errors:

final void ifStatement(boolean condition) {
  if (condition); else;
}

Not very useful I'd say. So perhaps we could use like the following:

final void ifStatement() {
  if (test()) {
    actionOne();
    actionTwo();
  } else;
}

The if block won't feel lonely; the else keeps it company.

Finally, let's look at the do statement. The following also compiles without errors:

final void doWhile(boolean condition) {
  do; while(condition);
}

Be careful if calling this method with a true condition.

All of the examples run without errors as well. Though some might end up in an infinite loop.

By itself

We can use the empty statement by itself.

The following method compiles without errors:

final void doesNothing() {
  ;
  
  ;;
  
  ;;;
}

But as the method name says it does nothing.

Blocks and labeled statements

We can also use the empty statement with blocks and labeled statements.

The following example compiles without errors:

final void blocksAndLabels() {
  {; {;} ;; foo:; bar:;}
}

It also executes without errors but it does nothing.

Here's a commented version that explains it:

final void blocksAndLabels() {
  // a block
  {
    // a single empty stmt
    ; 
    // a block w/ a single empty stmt
    {;}
    // two consecutive empty stmts
    ;;
    // labeled (foo) empty statement
    foo:;
    // labeled (bar) empty statement
    bar:;
  }
}

It goes without saying that this is not idiomatic Java. In other words, you should not write code like this.

What is it for?

Most, if not all, examples shown so far are not practical nor idiomatic.

So a question one might have is: what is a practical, real world use-case for the empty statement?

I believe a use-case is when performing "busy waiting"

Consider the following example:

public class UseCase {
  private int count;

  public static void main(String[] args) {
    var useCase = new UseCase();

    useCase.startService();
  }

  public void startService() {
    startExternalService();

    while (!externalReady());

    System.out.println("Started!");
  }

  private boolean externalReady() {
    return count++ > 1_000_000_000;
  }

  private void startExternalService() {
    System.out.println("Starting external...");
  }
}

It represents a hypothetical service which depends on a second external service.

We use it by calling the startService method:

public void startService() {
  startExternalService();

  while (!externalReady());

  System.out.println("Started!");
}

Notice how the while statement makes use of an empty statement.

The method starts the external service then busy waits until the service is ready.

Thread.onSpinWait

But... the previous example using the empty statement burns CPU cycles.

So, though not strictly required, it is better to tell the CPU that you are busy waiting for something.

JDK 9 introduced the Thread::onSpinWait method. So our startService method becomes:

public void startService() {
  startExternalService();

  while (!externalReady()) {
    Thread.onSpinWait();
  }

  System.out.println("Started!");
}

So no more empty statement...

Until the next issue of Objectos Weekly

So that's it for today. I hope you enjoyed reading.

The source code of all of the examples are in this GitHub repository.

Please send me an e-mail if you have comments, questions or corrections regarding this post.