Delayed initialization of immutable variables

I often used scala lazy val idiom and I would like to achieve something similar in Java. My main problem is that to build some value I need a different value, which is unknown during the construction of the object, but I do not want to change it later. The reason is that I use the GUI library, which initiates the object on my behalf, and calls another method when everything I need is created when I know the values ​​I need.

Here are the properties I'm trying to achieve:
* The immutability of my variable.
* Initialization in a different method than the constructor.

I do not think this is possible in Java, since only final achieves the immutability of the variable and final variables cannot be initialized outside the constructor.

What will be closest in Java to what I'm trying to achieve?

+4
source share
2 answers

One way to do this would be to push the actual instance of the value in question into another class. This will be final, but will not actually be created until the class is loaded, which is deferred until it is needed. Something like the following:

 public class MyClass { private static class Loader { public static final INSTANCE = new Foo(); } Foo getInstance() { return Loader.INSTANCE; } } 

This will lazily initialize Foo as needed.

If you absolutely need Foo be an instance variable of your top-level class, I can't figure out how to do this. The variable must be filled in the constructor, as you noted.

Actually, I don’t know exactly how Scala works, but I assume that it sets the lazy val variable to some thunk, which is replaced with the actual object on the first evaluation. Scala can, of course, do this by replacing the usual access modifiers in this case, but I don’t think you can transparently do this in Java. You can declare a field, for example. a Future<Foo> , which creates the value on the first call and caches it from this point, but it is not referentially transparent, and by the definition of final I see no way around it.

+5
source

Andrzej's answer is good, but there is also a way to do this without changing the source code. Use AspectJ to capture constructor calls and return uninitialized objects:

 pointcut lazyInit() : execution(* com.mycompany.expensiveservices.*.init(*)); void around() : lazyInit() && within(@Slow *) { new Thread(new Runnable(){ @Override public void run(){ // initialize Object in separate thread proceed(); } } } 

Given this aspect, all object constructors marked with @Slow annotations will execute in a separate thread.

I did not find the link to the link, but please read Ramnivas Laddad's AspectJ in Action for more information.

+1
source

All Articles