If I want to define Singleton , then it’ll be something like this:

A Singleton is a software design pattern that guarantees a class has one instance only and a global point of access to it is provided by that class. Singleton Pattern ensures that only one instance would be created and it would act as a single point of access thereby ensuring thread safety.

In java code, it’ll look like this:

public class Singleton {



private static Singleton instance;



private Singleton() {

}



public static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

But the above codes are dangerous, especially if it’s used in different threads. If two threads access this singleton at a time, two instances of this object could be generated.

class Singleton {



private static Singleton instance = null;



private Singleton() {

}



private synchronized static void createInstance() {

if (instance == null) {

instance = new Singleton();

}

}



public static Singleton getInstance() {

if (instance == null) createInstance();

return instance;

}

}

The synchronized keyword ensures that there are no thread interferences when creating the instance.

If you want to recreate this in Kotlin, then the code close to it will be:

class Singleton private constructor() {



private object HOLDER {

val INSTANCE = Singleton()

}



companion object {

val instance: Singleton by lazy { HOLDER.INSTANCE }

}

}

In this case, The by lazy{} indicates it will be computed on the first access only. The evaluation of lazy properties is synchronized, the value is computed only in one thread, and all threads will see the same value.

Kotlin has a default implementation of the above requirement, which is

object Singleton

Yeah!!!. That’s it. Only one line of code and you can avoid all those lines of code. An object is just a data type with a thread-safe singleton implementation.

Object declarations

object DataProviderManager {

fun registerDataProvider(provider: DataProvider) {

// ...

}



val allDataProviders: Collection<DataProvider>

get() = // ...

}

Just like a variable declaration, an object declaration is not an expression, and cannot be used on the right-hand side of an assignment statement. Object declaration’s initialization is thread-safe.

To refer to the object, we use its name directly.

DataProviderManager.registerDataProvider(...)

Objects can have supertypes:

object DefaultListener : MouseAdapter() {

override fun mouseClicked(e: MouseEvent) { ... }



override fun mouseEntered(e: MouseEvent) { ... }

}

Summarize: