Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does a java object become non-null during construction?

Say you are creating a java object like so:

SomeClass someObject = null;
someObject = new SomeClass();

At what point does the someObject become non-null? Is it before the SomeClass() constructor runs or after?

To clarify a little, say if another thread was to check if someObject was null while the SomeClass() constructor was halfway through completion, would it be null or non-null?

Also, what would be the difference if someObject was created like so:

SomeClass someObject = new SomeClass();

Would someObject ever be null?

like image 486
Lehane Avatar asked Mar 25 '09 14:03

Lehane


People also ask

Should we check null for every object in Java?

An aggressively safe strategy could be to check null for every object. However, this causes a lot of redundant null checks and makes our code less readable. In the next few sections, we'll go through some of the alternatives in Java that avoid such redundancy.

How to avoid NullPointerException in Java?

A common way of avoiding the NullPointerException is to check for null: In the real world, programmers find it hard to identify which objects can be null. An aggressively safe strategy could be to check null for every object. However, this causes a lot of redundant null checks and makes our code less readable.

Why is it so hard to handle null variables in Java?

Overview Generally, null variables, references and collections are tricky to handle in Java code. They are not only hard to identify but also complex to deal with. As a matter of fact, any miss in dealing with null cannot be identified at compile time and results in a NullPointerException at runtime.

How to manage Null contracts in static code analysis?

Static code analysis tools help improve the code quality a great deal. And a few such tools also allow the developers to maintain the null contract. One example is FindBugs. FindBugs helps manage the null contract through the @Nullable and @NonNull annotations.


1 Answers

If another thread were to check the someObject variable "during" construction, I believe it may (due to quirks in the memory model) see a partially initialized object. The new (as of Java 5) memory model means that any final fields should be set to their values before the object becomes visible to other threads (so long as the reference to the newly created object doesn't escape from the constructor in any other way) but beyond that there aren't many guarantees.

Basically, don't share data without appropriate locking (or guarantees given by static inializers etc) :) Seriously, memory models are seriously tricky, as is lock-free programming in general. Try to avoid this becoming a possibility.

In logical terms the assignment happens after the constructor runs - so if you observe the variable from the same thread it will be null during the constructor call. However, as I say there are memory model oddities.

EDIT: For the purposes of double-checked locking, you can get away with this if your field is volatile and if you're using Java 5 or higher. Prior to Java 5 the memory model wasn't strong enough for this. You need to get the pattern exactly right though. See Effective Java, 2nd edition, item 71 for more details.

EDIT: Here's my reasoning for arguing against Aaron's inlining being visible in a single thread. Suppose we have:

public class FooHolder
{
    public static Foo f = null;

    public static void main(String[] args)
    {
        f = new Foo();
        System.out.println(f.fWasNull);
    }
}

// Make this nested if you like, I don't believe it affects the reasoning
public class Foo
{
    public boolean fWasNull;

    public Foo()
    {
        fWasNull = FooHolder.f == null;
    }
}

I believe this will always report true. From section 15.26.1:

Otherwise, three steps are required:

  • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
  • Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the value of the right-hand operand is converted to the type of the left-hand variable, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

Then from section 17.4.5:

Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.

If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.

  • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
  • There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object.
  • If an action x synchronizes-with a following action y, then we also have hb(x, y).
  • If hb(x, y) and hb(y, z), then hb(x, z).

It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

In other words, it's okay for weird stuff to happen even within a single thread but that mustn't be observable. In this case the difference would be observable, which is why I believe it would be illegal.

like image 71
Jon Skeet Avatar answered Oct 05 '22 23:10

Jon Skeet