Java compilation error for instance level Target variables and not setting for method level local variables

Why doesn't the java compiler give any kind of compile-time error for method-level local final variables when we don't initialize them?

(but it gives en error for final instance level variables when they are not initialized).

public class FinalKeyword
{
    final int j; // error: the blank final field j may not have been initialized.

    public static void main(String[] args)
    {
        final int k; // not giving any Compile time error!
    }
}

      

+3


source to share


3 answers


Thing: once you change your method main()

to

final int k;//Not Giving any Compile time error
System.out.println(k); //different story now!

      

You will get the error k not initialized too!

Point:

  • the compiler has to make sure that the other source code that is not showing right now ... is able to do new FinalKeyword()

    without issue. Thus, it cannot let you keep j

    uninitialized.
  • but this method main()

    ... even if another method calls this method main()

    , that's ok. The method does nothing! In other words, it's not a problem to define a variable that is not used in the method! Because there is no way to access this variable!

The compiler should prevent you from getting into situations where you "stumble" over an uninitialized variable. When you call a method that has variables like this ... but never uses them - it just "doesn't care".



And with surprise: when we go with

public class FinalTest {
  public static void main(String args[]) {
    final int k;
  }
}

      

and compile this; and then we use javap to get the decompiled bytecode:

public static void main(java.lang.String[]);
  Code:
   0: return     

      

This is one of the rare cases where javac will optimize a little - by simply discarding unused variables. Bonus fun fact: even if you change my example to, k=5;

you'll find that the class file still only contains return

!

+2


source


j

- class field. k

not. You need to initialize the final fields in the class constructor. Your class uses your implicit default constructor, which does not initialize fields.

The reason it doesn't give you a warning for a local variable is because you are not using it. If you were using an uninitialized local variable, you would get an error:



public static void main(String[] args)
{
    final int k;
    if (k < 5) {
        // whatever
    }
}

      

As to why the compiler is not smart enough to know that you are not using the field either, I'm not sure. This seems to be more complicated due to inheritance, access levels, etc.

0


source


In general, if the compiler is faced with a situation where final

it can be accessed uninitialized or specified during initialization, an error occurs.

The fields of the class final

must be initialized as someone can access them at any time. If it's private, protected, or public, other code can access the field directly, and they expect it to be initialized. Even if a field private

, someone can reflect it and try to access it, so the compiler shouldn't ignore it.

Local methods final

are internal to a method, and there is no way to reflect within a method without changing some bytecode, so the compiler shouldn't be that strict. Instead, the compiler does flow parsing control to display when a field is assigned and not assigned, and it will throw an error if it is used, or it might not, and will be contained if it is never used or is not used. definitely appointed.

void meth0() {
    final String s;
    // Compiler: s is never used; I don't care.
}

void meth1() {
  final String s;
  // s is definitely unassigned
  if(something()) {
      s = "something";
      // s is definitely assigned
      System.out.println(s);
  } else {
      // s is definitely unassigned
      s = "other";
      // s is definitely assigned
      System.out.println(s);
  }
  // if-branch def. assigns s, else-branch def. assigns s
  // Ergo: s is def. assigned
  somethingElse(s);
  // Compiler: control flow checks out; code is valid
}

void meth2() {
  final String s;
  // def. unass.
  if(something()) {
    s = "something";
    // def ass.
  }
  // s is in undetermined state
  // s = ""; // s may be assigned; error
  // use(s); // s may not be assigned; error
  // s is now totally unusable. Nice job breaking it, hero!
}

      

0


source







All Articles