For this code:
import java.io.IOException
object Test {
init {
throw IOException("should see me")
}
fun helloWorld(): String = "Hello, world!"
}
fun main(args: Array<String>) {
try {
println("1: ")
System.out.flush()
println(Test.helloWorld())
} catch (e: ExceptionInInitializerError) {
println("Catched")
System.out.flush()
}
println("2: ")
System.out.flush()
println(Test.helloWorld())
}
I would have expected to see the “should see me” exception message also on the second call of Test.helloWorld()
, but instead I’m getting java.lang.NoClassDefFoundError: Could not initialize class Test
.
While I get that an object
usually should only get initialized once, wouldn’t it make sense to retry if it failed? In my real case, the condition of the exception thrown in the constructor is more complex and depends on external resources that could have changed over time. But even if the condition had not changed, it would be much more readable to see the original exception message instead of a NoClassDefFoundError
.
Any comments?
That is an expected behavior on JVM, as objects are initialized when the corresponding class is loaded by JVM and a class that had failed to initialize on JVM would produce the exception that you observe on subsequent attempt to use it. See section 5.5 of JVM specification:
If the Class object for C is in an erroneous state, then initialization is not possible. Release LC and throw a NoClassDefFoundError.
Ok, but wouldn’t it be possible for Kotlin to avoid the class being put in an “erroneous state” in such a case, but pretend it uninitialized, so initialization is tried again?
If the class intialization changes over time, because it depends on external circumstances, doesn’t it make much more sense then in that case to have a class instead of an object and create a new instance of the class when you need it?
Otherwise the part of behaviour that can fail depending on external circumstances, should not be part of the constructor but of some other class method that is not called during class init.
There does not seem to be a way in JVM to do so.
IMHO, it is a bad style when singleton object initialization depends on external circumstances. You should try to use some kind of dependency injection for those cases.
1 Like
Yeah, that’s probably the way I’ll go. Thanks.