Kotlin – Use `object` for Singleton Patterns

In software development, a singleton is a design pattern that ensures a class has only one instance and provides a global access point to it. While implementing singletons in Java requires additional effort, Kotlin makes it simpler using the object keyword.

In this article, we will learn how to create a singleton in Kotlin using object, compare it with Java, and explore examples of how this pattern is used in practice.

Table of contents

1. Singleton in Java

In Java, implementing a thread-safe singleton requires additional steps, such as using synchronized blocks or static inner classes.

Java Singleton Example

Singleton.java

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
        // Private constructor to prevent instantiation
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public void showMessage() {
        System.out.println("Hello from Java Singleton!");
    }
}

This implementation ensures lazy initialization and thread safety, but it’s verbose and requires extra boilerplate code.

2. Singleton in Kotlin using `object`

Kotlin simplifies singleton creation using the object keyword, which automatically:

  • Ensures a single instance.
  • Provides thread-safety without extra synchronization.
  • Simplifies code structure.

Kotlin Singleton Example

Singleton.kt

object Singleton {
    fun showMessage() {
        println("Hello from Kotlin Singleton!")
    }
}

fun main() {
    Singleton.showMessage()
}

3. Why is Kotlin’s `object` Better?

Feature Java Singleton Kotlin object Singleton
Thread Safety Requires explicit handling (synchronized) Built-in by default
Lazy Initialization Needs additional code (volatile, synchronized) Automatically lazy
Concise Code More lines of code Very simple (object keyword)
Global Access Needs a static method Directly accessible

4. Real-World Example: Singleton for Configuration Manager

Java Implementation

ConfigManager.java

public class ConfigManager {
    private static ConfigManager instance;
    private Map<String, String> config = new HashMap<>();

    private ConfigManager() { }

    public static ConfigManager getInstance() {
        if (instance == null) {
            instance = new ConfigManager();
        }
        return instance;
    }

    public void setValue(String key, String value) {
        config.put(key, value);
    }

    public String getValue(String key) {
        return config.get(key);
    }
}

Kotlin Implementation

ConfigManager.kt

object ConfigManager {
    private val config = mutableMapOf<String, String>()

    fun setValue(key: String, value: String) {
        config[key] = value
    }

    fun getValue(key: String): String? {
        return config[key]
    }
}

fun main() {
    ConfigManager.setValue("theme", "dark")
    println(ConfigManager.getValue("theme")) // Output: dark
}

Use Case:
This is useful for managing global application settings like themes, API keys, and user preferences.

5. Real-World Example: Singleton for Logger

Logging is an essential feature in applications, and ensuring a single instance of a logger is a common use case for a singleton pattern.

Java Logger Singleton

Logger.java

public class Logger {
    private static Logger instance;

    private Logger() { }

    public static Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("LOG: " + message);
    }
}

Kotlin Logger Singleton

Logger.kt

object Logger {
    fun log(message: String) {
        println("LOG: $message")
    }
}

fun main() {
    Logger.log("Application started")
    Logger.log("User logged in")
}

Use Case:
The Logger singleton ensures that all log messages go through a single instance, preventing duplicate logging setups across the application.

6. Key Takeaways

  • Kotlin’s object keyword makes singleton implementation easy by handling thread safety and lazy initialization automatically.
  • Java singletons require extra boilerplate code to ensure thread safety.
  • Using Kotlin object is the recommended way to implement the singleton pattern in modern applications.
  • Real-world applications include:
    • Configuration Managers (store global settings)
    • Logging Systems (ensure consistent logging)
    • Database Connections (single access point)

7. Conclusion

Kotlin simplifies the singleton pattern with the object keyword, making it cleaner and safer than Java’s approach.

8. References

mkyong

Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities.

0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments