19

Consider the following code snippet in Java. It won't compile.

package temppkg;

final public class Main
{
    private String x;
    private int y;

    private void show()
    {
        String z;
        int a;

        System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error.
        System.out.println(y); // Works fine displaying its default value which is zero.
        System.out.println(z.toString()); // Causes a compile-time error - variable z might not have been initialized.
        System.out.println(a); // Causes a compile-time error - variable a might not have been initialized.
    }

    public static void main(String []args)
    {
        new Main().show();
    } 
}

Why do the class members (x and y) declared in the above code snippet not issue any compile-time error even though they are not explicitly initialized and only local variables are required to be initialized?

Psi
  • 83
  • 1
  • 7
Lion
  • 18,729
  • 22
  • 80
  • 110
  • 5
    +1 This turned out to be a really good question - I'm surprised how many Java programmers don't know that class members _are_ initialized when created. – Paul Dec 15 '11 at 15:14
  • 1
    Maybe the question should be "why does the compiler initialise members with default values, but not local variables". I would agree that it's not very intuitive that in your example, `x` is initialized to `null`, but `z` isn't. Even if it makes sense, once one thinks about the reasons given in the answers below. – mth Dec 15 '11 at 15:19
  • @mth, in my answer below you'll find your answer. The introduction in the Java Language Spec says, "...the Java programming language does not automatically initialize local variables in order to avoid masking programming errors." – Paul Dec 15 '11 at 15:21
  • possible duplicate of [Why are local variables not initialized in Java?](http://stackoverflow.com/questions/415687/why-are-local-variables-not-initialized-in-java) – Raedwald Mar 11 '14 at 13:04

5 Answers5

23

When in doubt, check the Java Language Specification (JLS).

In the introduction you'll find:

Chapter 16 describes the precise way in which the language ensures that local variables are definitely set before use. While all other variables are automatically initialized to a default value, the Java programming language does not automatically initialize local variables in order to avoid masking programming errors.

The first paragraph of chapter 16 states,

Each local variable and every blank final field must have a definitely assigned value when any access of its value occurs....A Java compiler must carry out a specific conservative flow analysis to make sure that, for every access of a local variable or blank final field f, f is definitely assigned before the access; otherwise a compile-time error must occur.

The default values themselves are in section 4.12.5. The section opens with:

Each class variable, instance variable, or array component is initialized with a default value when it is created.

...and then goes on to list all the default values.

The JLS is really not that hard to understand and I've found myself using it more and more to understand why Java does what it does...after all, it's the Java bible!

Pang
  • 9,564
  • 146
  • 81
  • 122
Paul
  • 19,704
  • 14
  • 78
  • 96
  • 7
    "When in doubt, check the Java Language Specification (JLS)." I don't think that's a good suggestion to some absolute beginner. A book or some article would be a better suggestion. But the answer is great. +1. – Bhesh Gurung Dec 15 '11 at 15:27
  • 1
    I don't think this answers the question. Why can't the same analysis that's done for local variables be applied to class members? Why is there a difference between the two? – John Kugelman Jul 06 '20 at 02:09
3

Why would they issue a compile warning?, as instance variables String will get a default value of null, and int will get a default value of 0.

The compiler has no way to know that x.toString(), will cause a runtime exception, because the value of null is not actually set till after runtime.

Oscar Gomez
  • 18,436
  • 13
  • 85
  • 118
2

In general the compiler couldn't know for sure if a class member has or has not been initialized before. For example, you could have a setter method that sets the value for a class member, and another method which accesses that member. The compiler can't issue a warning when accessing that variable because it can't know whether the setter has been called before or not.

I agree that in this case (the member is private and there is no single method that writes the variable) it seems it could raise a warning from the compiler. Well, in fact you are still not sure that the variable has not been initialized since it could have been accessed via reflexion.

Thins are much easier with local variables, since they can't be accessed from outside the method, nor even via reflexion (afaik, please correct me if wrong), so the compiler can be a bit more helpful and warn us of uninitialized variables.

I hope this answer helps you :)

Fawzan
  • 4,738
  • 8
  • 41
  • 85
Riseven
  • 62
  • 3
  • 2
    No. Class members are initialized with default values when created. See [Java Language Spec 4.12.5](http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.5). – Paul Dec 15 '11 at 15:13
  • @Paul which would then raise the question why are they initialized with default values? And if he replaces the can't with couldn't i think it s a good argument. +1 – Stefan Dec 15 '11 at 15:50
  • @Paul: You are right in that my wording is not technically accurate since they are initialized. However I feel that what Lion was interested was not the spec, but the rationale behind the spec, hence my explanation. Anyways thanks for the correction, I'm editing my answer as suggested by Stefan to reflect that. – Riseven Dec 16 '11 at 07:56
1

Class members could have been initialized elsewhere in your code, so the compiler can't see if they were initialized at compilation time.

LaGrandMere
  • 10,265
  • 1
  • 33
  • 41
  • 3
    No. They are initialized with default values when created. See [Java Language Spec 4.12.5](http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.5). – Paul Dec 15 '11 at 15:10
1

Member variables are automatically initialized to their default values when you construct (instantiate) an object. That holds true even when you have manually initialized them, they will be initialized to default values first and then to the values you supplied.

This is a little little lengthy article but it explains it: Object initialization in Java

Whereas for the local variables (ones that are declared inside a method) are not initialized automatically, which means you have to do it manually, even if you want them to have their default values.

You can see what the default values are for variables with different data types here.

The default value for the reference type variables is null. That's why it's throwing NullPointerException on the following:

System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error.

In the following case, the compiler is smart enough to know that the variable is not initialized yet (because it's local and you haven't initialized it), that's why compilation issue:

System.out.println(z.toString()); // "Cuases a compile-time error - variable z might not have been initialized.
Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142