Bathsheba
Bathsheba

Reputation: 234715

Netbeans Java complaining about final variable not being initialised

Consider this code:

final MyClass myObject;
try {
    myObject = new MyClass(...)
} catch (MyClassException){
    // terminate
    System.exit(1);
}

myObject.doSomething();

The problem is that the Netbeans editor / parser thinks that .doSomething() could be called on an unitialised object which, of course, is not the case.

Is there an normal / standard pattern for circumventing this? I could call into a function but would rather not do that. I'd also rather not enclose the whole block in the try catch block since nothing else throws MyClassException

I'm not (yet ;-) ) an expert on Java grammar and patterns so am hope I'm missing something obvious.

Upvotes: 3

Views: 208

Answers (6)

stackh34p
stackh34p

Reputation: 9009

The point of the final variables and members is to always be initialized. Although your code will never call doSomething, it will leave the final field undefined. This becomes an issue if you add a finally clause to the try-catch block - you may enter the finally clause when exception occurs and the myObject will not be available, which the compiler must avoid.

final MyClass myObject;
try {
    myObject = new MyClass(...); // constructor may throw exception
} catch (MyClassException){
    // terminate
    System.exit(1);
} finally {
    // what does myObject point to now, if the constructor threw exception?
}

myObject.doSomething();

A quick solution is to move the doSomething call in the try block:

final MyClass myObject;
try {
    myObject = new MyClass(...);
    myObject.doSomething();
} catch (MyClassException){
    // terminate
    System.exit(1);
}

This should work fine as long as doSomething does not also throw a MyClassException. If it throws such exception, you probably need to differentiate the case whether it came from the constructor or the method (if of course this matters to your logic).

Upvotes: 1

assylias
assylias

Reputation: 328618

The problem is that the Netbeans editor / parser thinks that .doSomething() could be called on an unitialised object which, of course, is not the case.

It is the case: nothing prevents you from using a SecurityManager which will forbid System.exit() from exiting the JVM. In that situation, the next statement could be executed.

From a Java grammar perspective, the compiler needs to prove that myObject is definitely assigned when you call myObject.doSomething();.

The JLS specifies the situations in which this can be done. In particular, the only statements that can be used to determine that the next instruction(s) will not be executed are break, continue, return, and throw. So the compiler is not allowed to consider that System.exit(1); will prevent the next statement from being executed.

Upvotes: 1

Vladimir
Vladimir

Reputation: 9753

You initialize your object in try block, which may throw exception, leaving object uninitialized.

In your catch block, you stop your program, but System.exit(1) does not stop method execution, instead, it terminates currently running JVM - and for compiler it's just another method you call if an exception is thrown.

return actually stops method execution - so no code beyond return; is reached. You can modify your catch block as following:

catch (MyClassException){
    // terminate
    System.exit(1);
    return;
}

Compiler won't complain about myObject not being initialized this way.

EDIT

NB: if you put myObject.doSomething(); in finally block compiler WILL complain, since finally is executed even after return.

finally {
    // compiler error
    myObject.doSomething();
}

Upvotes: 5

Bathsheba
Bathsheba

Reputation: 234715

This is the best I can do:

final MyClass myObject;
{
    MyClass local = null;
    try {
        local = new MyClass(...)
    } catch (MyClassException){
        // terminate
        System.exit(1);
    }
    myObject = local;
}

myObject.doSomething();

Upvotes: 1

aran
aran

Reputation: 11860

Netbeans editor / parser thinks that .doSomething() could be called on an unitialised object which, of course, is not the case.

You are wrong here. You are in fact trying to initialize the variable. The compiler doesn't "trust" in the initialization and the reason is simple: it could throw an exception, which you could catch but not throw a new RuntimeException() or make a System.exit(1). For example:

try {
    myObject = new MyClass(...)
} catch (MyClassException e){
    // hey I catch this but do nothing lmao yolo
    e.printStackTrace();
}

myObject.doSomething();

you could catch the exception, print the stacktrace and continue the program, and the consequence would be a NullPointerException.

Upvotes: 1

ragklaat
ragklaat

Reputation: 946

The case is that outside the try/catch block you try to call a method on a possibly not instantiated object. That is because the try/catch block may throw exceptions so the object is not created, therefore in this case you will not have an object when you try to call the doSomething() method on it.

If you include the method call in the try/catch block, it will work.

You can find related information here: Java Tutorials: Lesson: Exceptions

Upvotes: 1

Related Questions