[Solved] Java Lambda Consumer Compilation behavior


The problem is that your two lambdas could be using the value of datamap before it has been initialized. At least, that is what the JLS definite assignment rules are saying.

This is what will happen when the ConsumerTest object is created:

  1. The bare object is allocated.
  2. The superclass constructor is called (Object()) which does nothing.
  3. The instance field declarations are “executed”
    1. dataMap … not initialized
    2. allConsumers … not initialized
    3. evenConsumer … initialized to the value of the first lambda
    4. oddConsumer … initialized to the value of the second lambda
  4. The body of the constructor is executed
    1. dataMap is initialized
    2. allConsumers is initialized.

The problem is (conceptually) this. Those lambdas could in theory be passed anywhere as soon as they have been initialized. If the recipient decides to use them before the dataMap variable has been initialized, then what would the lambdas see?

  • If the dataMap variable was not final, then they would see the default initial value; i.e. null.
  • In the case where dataMap is final, they are not allowed to see anything. The dataMap variable must be definitely assigned before it is used … since it is final. The JLS is quite particular on this point.

(Try writing any code that reads a final variable before it is initialized and you will see what I mean.)

In essence, this is just a rather unexpected (though perfectly logical) consequence of the normal Java rules for final initialization.


I can think of three solutions in this case:

  • Don’t make the dataMap variable final. It doesn’t need to be.
  • Initialize dataMap in its declaration rather than in the constructor.
  • Initialize the lambdas inside the constructor, after initializing dataMap. (Ugly … but it would work.)

1

solved Java Lambda Consumer Compilation behavior