lazy singletons are completely useless*. The aim is, presumably, that the singleton is not 'initialized' or 'takes up memory'. But, good news! It won't. Not until some code touches the singleton class, at which point, well, you needed that initialization anyway. Thus:
public class Lazy1 {
private static final Lazy1 INSTANCE = new Lazy1();
private Lazy1() {} // prevent instantiation by anybody else
public static Lazy1 getInstance() { return INSTANCE; }
}
Does what you want: It is simpler, not buggy, and fast. In contrast to your take, which is quite slow (a synchronized lock every time, even on hour 100, after a million calls to getinstance. However, remove the synchronized and you end up in a buggy scenario. You can try to get around that in turn with volatiles and double locking, but now you have quite complicated code that is almost impossible to test, and which still cannot outperform the fast locking that the classloader itself gives you).
You may think this is non-lazy, but that's false. Try it: print something in that constructor and observe when it prints. It'll print only when the first getInstance()
is ever invoked.
Given that it is a singleton, if you need some property (such as 'a scanner') to operate, you have only two options:
- The singleton is in an invalid state until it is initialized
All methods that need this state check if the state is valid and throw if it is not:
public class Lazy1 {
private static final Lazy1 INSTANCE = new Lazy1();
private Lazy1() {} // prevent instantiation by anybody else
public static Lazy1 getInstance() { return INSTANCE; }
private Scanner scanner;
public void menu() {
if (scanner == null) throw new IllegalStateException("Uninitialized");
// ....
}
public void init(Scanner s) {
this.scanner = s;
}
}
Every method that needs the 'scanner state' should first check, then throw.
- The singleton doesn't have state. Instead, its methods take the required state as parameter
Your Lazy1 doesn't have, say, public void menu()
. It has public void menu(Scanner s) {}
- every time any code calls it, it passes scanner along.
*) There is actually a point, but only if some code refers to the Lazy1 class without getting the singleton. If you're doing that, you probably need to fix your code; that'd be rather weird.