Reputation: 234715
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
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
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
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
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
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
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