After my success with extending enum - I thought I would try to make Singleton creation as simple as possible since Java-8 makes Multitons comparatively easy.My aim was to create a class which is a Singleton solely by the simple fact that it implements a Singleton interface. Unfortunately there is a little baggage required but it doesn't look too bad. I don't think I would use it in a real setting as it still doesn't provide the level of simplicity I am looking for but as a prototype it seems to work.Can anyone see any ways of simplifying it further? I would like to aim for as little as possible in the TestSingleton class.I would also like to see a way of forcing, or even pre-defining the getInstance() method but that looks impossible to me.Here's the Multiton it uses:/** * A classic Multiton making use of lambdas to delay the create. * * * @author OldCurmudgeon * @param <K> - The type that can create. */public class Multiton<K extends Multiton.Creator> {    /**     * The storage.     *     * Store only Object because they must all be different types.     */    private final ConcurrentMap<K, Object> multitons = new ConcurrentHashMap<>();    /**     * The keys must be capable of creating their values.     */    public interface Creator {        public abstract Object create();    }    /**     * The getter.     *     * @param <V> - The type of the value that should be returned.     * @param key - The unique key behind which the value is to be stored.     * @param type - The class of the value returned.     * @return - The value stored (and perhaps created) behind the key.     */    public <V> V get(final K key, Class<V> type) {        // Has it run yet?        Object o = multitons.get(key);        // A null value means not yet.        if (o == null) {            // Use a lambda to only do the create if it is still absent.            o = multitons.computeIfAbsent(key, k -> k.create());        }        return type.cast(o);    }    // Some simple testing.    enum E implements Creator {        A {                    @Override                    public String create() {                        return Face;                    }                },        B {                    @Override                    public Integer create() {                        return 0xFace;                    }                },        C {                    @Override                    public Void create() {                        return null;                    }                };    }    public static void main(String args[]) {        try {            Multiton<E> m = new Multiton<>();            String face1 = m.get(E.A, String.class);            Integer face2 = m.get(E.B, Integer.class);            System.out.println(Face1:  + face1 +  Face2:  + Integer.toHexString(face2));        } catch (Throwable t) {            t.printStackTrace(System.err);        }    }}And my attempt at a interface Singleton, along with TestSingleton to demonstrate:/** * Implement this and you're a singleton. * * @author OldCurmudgeon * @param <T> - The type we are a Singleton of. */public interface Singleton<T extends Singleton<T>> {    /**     * A Creator command to create the singleton.     *     * @param <T> - The actual Singleton type.     */    class Creator<T extends Singleton<T>> implements Multiton.Creator {        final Supplier<Singleton<T>> singletonConstructor;        final Class<T> singletonClass;        public Creator(Supplier<Singleton<T>> constructor, Class<T> clazz) {            this.singletonConstructor = constructor;            this.singletonClass = clazz;        }        @Override        public Singleton<T> create() {            return singletonConstructor.get();        }    }    /**     * Use one Multiton to keep track of all singletons.     */    static final Multiton<Creator> multitons = new Multiton<>();    /**     * The getInstance must create the object if need be.     *     * @param <T> - The type of the singleton created.     * @param creator - A Creator for the class.     * @return - the Singleton.     */    static <T extends Singleton<T>> T getInstance(Creator<T> creator) {        return multitons.get(creator, creator.singletonClass);    }    /**     * A test singleton.     */    class TestSingleton implements Singleton<TestSingleton> {        /**         * My constructor should be called only once.         */        public TestSingleton() {            System.out.println(Creating a TestSingleton!);        }        /**         * A Lightweight creator that can therefore be static.         *         * This must be static final as it is the key in the Multiton map.         */        private static final Creator creator = new Creator(TestSingleton::new, TestSingleton.class);        /**         * Implement the expected getInstance() - sadly not forced.         *          * @return - The same TestSingleton for ever.         */        public static TestSingleton getInstance() {            return Singleton.<TestSingleton>getInstance(creator);        }    }    public static void main(String args[]) {        try {            TestSingleton s1 = TestSingleton.getInstance();            TestSingleton s2 = TestSingleton.getInstance();            if (s1 == s2) {                System.out.println(OK!);            }        } catch (Throwable t) {            t.printStackTrace(System.err);        }    }}
Can we now `implement Singleton` using Java 8?
java;singleton
ConcurrentMapAs was pointed out in the comments: in the Multiton.get() method:public <V> V get(final K key, Class<V> type) {    // Has it run yet?    Object o = multitons.get(key);    // A null value means not yet.    if (o == null) {        // Use a lambda to only do the create if it is still absent.        o = multitons.computeIfAbsent(key, k -> k.create());    }    return type.cast(o);}There's no reason to have the double-check. The computeIfAbsent already does that:public <V> V get(final K key, Class<V> type) {    return type.cast(multitons.computeIfAbsent(key, k -> k.create()));}GenericsI have taken, and played with your code. It became apparent that there is no reason to have a generic type on the Multiton class. You only really use it as Multiton<Creator>, and that's the broadest sense of the Generics anyway. The more I played with it, though, the more I realized that your logic is in the wrong place. The right place would be to have more in the Multiton, and to get rid of the Singleton class entirely.... There is no reason for the Singleton interface. It creates a lot of ugliness anyway, because the interface cannot have private static members, so the Multiton instance needs to be non-private, making it a resource leak.Consider the following Multiton:import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.function.Supplier;/** * A classic Multiton making use of lambdas to delay the create. * * * @author OldCurmudgeon * @param <K> - The type that can create. */public class Multiton {    /**     * The keys must be capable of creating their values.     */    public interface Creator<V> {        public Object create();        public V cast(Object value);    }    public static abstract class TypedCreator<A> implements Creator<A> {        private final Class<A> tclass;        public TypedCreator(Class<A> tclass) {            this.tclass = tclass;        }        @Override        public final A cast(Object value) {            return tclass.cast(value);        }    }    public static final class SuppliedCreator<A> extends TypedCreator<A> {        private final Supplier<A> supplier;        public SuppliedCreator(Class<A> tclass, Supplier<A> supplier) {            super(tclass);            this.supplier = supplier;        }        @Override        public Object create() {            return supplier.get();        }    }    /**     * The storage.     *     * Store only Object because they must all be different types.     */    private final ConcurrentMap<Creator<?>, Object> multitons = new ConcurrentHashMap<>();    /**     * The getter.     *     * @param <V> - The type of the value that should be returned.     * @param key - The unique key behind which the value is to be stored.     * @return - The value stored (and perhaps created) behind the key.     */    public <V, C extends Multiton.Creator<V>> V get(final C key) {        return key.cast(multitons.computeIfAbsent(key, k -> k.create()));    }}Of particular importance, note:there's no generic type for the Multiton. This is expected. All it needs is the public get() method, and the generics for that method are determined by the call arguments.... which is point 2....the generic type of the values are declared on the Creator (which is also the key). In other words, each key knows what the type of the value should be. This means that the generic type is 'recorded' at create time, rather than retrieve time. There's no need to pass a class in to the get() call since the class is actually part of the Creator.I created 2 'helper' classes that are Creator instances. These classes TypedCreator and SuppliedCreator are simpler ways to actually create anonymous, or Java-8 based Creators.Note that I can't see a convenient way to use a Singleton interface. The interface depends on a shared instance of the Multiton, so as a result, there needs to be some static data in the Singleton. As a consequence, an interface is the wrong language structure to use. An abstract class may be better. Still, the usage examples for the Multiton above are simple (in some common 'utility' class, or somewhere shared):public static final Multiton MULTITON = new Multiton();Then, whenever you have a need for a Singleton:public static final Multiton.Creator<String> HARDWORK = new Multiton.SuppliedCreator<>(String.class, () -> initializeHardWork());and then:String hardwork = MULTITON.get(HARDWORK);This can be encapsulated in to an abstract Singleton class as:public abstract class Singleton {    protected static final Multiton MULTITON = new Multiton();        }The Singleton class can then be used in various ways, here's an example:public class TestSingleton extends Singleton {    private static final Multiton.Creator<TestSingleton> KEY = new Multiton.SuppliedCreator<>(TestSingleton.class, TestSingleton::new);    public static final TestSingleton getInstance() {        return MULTITON.get(KEY);    }    private final String name;    private TestSingleton() {        try {            Thread.sleep(200);            name = Instance  + System.currentTimeMillis();            System.out.println(Slow Instance:  + name);            Thread.sleep(200);        } catch (InterruptedException e) {            throw new IllegalStateException(Interrupted , e);        }    }    @Override    public String toString() {        return name;    }    public static void main(String[] args) {        ExecutorService service = Executors.newFixedThreadPool(8);        for (int i = 0; i < 20; i++) {            service.execute(() -> {System.out.println(TestSingleton.getInstance());});        }    }}