When is a Singleton the right choice in Java, and what alternatives (like dependency injection) should you prefer?
answer
- one instance (fine) vs Singleton pattern (often avoid)
- hidden global state, hard to test, tight coupling
- prefer DI: create one, inject it, behind an interface
- Spring default scope = singleton bean
- stateless singletons dodge most problems
basics
~20 sUse a true Singleton only when there genuinely must be one instance, like a registry or a hardware accessor. For most shared services, create one instance and pass it where needed (dependency injection) instead, because hard-coded singletons are global state and hard to test.
solid answer
~50 sA Singleton is justified when one instance is a real invariant of the domain - a registry, a connection pool, the JVM's Runtime, a stateless helper that holds expensive shared resources. Even then, the classic 'getInstance() called everywhere' form is problematic: it is hidden global mutable state, it couples callers to a concrete class, and it makes unit testing hard because you cannot swap in a fake. The better default is dependency injection: create exactly one instance (often a container-managed singleton-scoped bean in Spring) and inject it into the objects that need it. That keeps the 'one instance' property while making the dependency explicit and the class testable behind an interface. So distinguish 'singleton the lifecycle' (one instance, fine) from 'Singleton the pattern' (static global access, usually avoid). When you do need the language form, the enum or holder idiom is the implementation to reach for.
go deeper
Knows a Singleton means one instance and that it is commonly used for shared things like config or logging.
Can name testability and global-state downsides and knows dependency injection is often the better way to share one instance.
Distinguishes 'one instance' (a scope concern) from the Singleton pattern, and consistently prefers DI behind an interface, reserving language singletons for genuine invariants.
Owns instance lifecycle/scope at the composition-root/container level, sets team guidance on when singletons are justified, and weighs stateless-shared-resource singletons vs container-managed beans vs per-request scope.
## 'One instance' vs 'the Singleton pattern' A crucial distinction: needing **one instance** of something is common and fine; using the **Singleton pattern** (a class that hands itself out via a static `getInstance()`) is a specific, often-criticized way to achieve it. ### When a true singleton is appropriate - The single instance is a genuine **invariant of the problem**: there is exactly one screen, one printer spooler, one running JVM. `Runtime.getRuntime()` is a legitimate example - there truly is one JVM. - A **stateless** object (or one that only holds immutable/shared resources) where extra copies would just waste memory - sharing one is safe. - A **registry** or **pool** whose whole job is to be the single coordination point. Notably, a **stateless** singleton avoids many of the usual sins: with no mutable state there is no cross-test contamination and no concurrency hazard from sharing. ### Why the pattern is criticized 1. **Hidden global state.** `Foo.getInstance()` can be called from anywhere, so a class's real dependencies are invisible in its constructor/signature. This makes the system harder to understand and reason about. 2. **Testability.** A static instance is hard to replace with a test double. If `getInstance()` returns a real database client, your 'unit' test now hits a database. Mutable singletons also leak state between tests, causing order-dependent flakiness. 3. **Tight coupling.** Callers depend on the concrete class, not an interface, violating the Dependency Inversion Principle and making substitution hard. 4. **Concurrency and lifecycle.** A mutable global is a shared-state magnet; and 'lives forever' is not always what you want (you may want per-request or per-session scope). ### The preferred alternative: dependency injection (DI) **Dependency injection** means an object receives its collaborators from outside (via constructor parameters) rather than fetching them itself. ```java class OrderService { private final PaymentGateway gateway; // an interface OrderService(PaymentGateway gateway) { this.gateway = gateway; } } ``` You still create **exactly one** `PaymentGateway` and pass it everywhere it is needed - so you keep the 'one instance' property - but: - the dependency is **explicit** (visible in the constructor), - the class depends on an **interface**, so tests can inject a fake, - the lifecycle/scope is controlled by the wiring code or a **DI container** (e.g. Spring), not hard-coded. In Spring, the default bean scope is `singleton` - the container creates **one** instance and injects it. This gives you single-instance semantics with none of the global-static, untestable downsides. That is why frameworks largely replaced hand-rolled singletons. ### Other alternatives / refinements - **Pass a collaborator as a parameter** (method or constructor) instead of reaching for a global - the simplest DI. - **An interface in front of the singleton**, so callers depend on the abstraction and can be tested against a fake even if a default singleton implementation exists. - **Enum or holder idiom** when you *do* implement the language singleton - they are the safe, concise forms. ### A decision heuristic - Is one instance a real domain invariant, and is the object stateless or holding only shared resources? A singleton (preferably enum/holder) is reasonable. - Otherwise - especially for stateful services you will want to test or vary - **inject one instance** via DI behind an interface. The senior/principal mindset: 'one instance' is a **scope/lifecycle** decision best owned by the composition root or DI container, not bolted onto the class via a static accessor.
- How does a Spring singleton-scoped bean differ from a classic getInstance() singleton?Both yield one instance, but the Spring bean's single instance is created and injected by the container, the dependency is explicit in the constructor, and it is typically coded against an interface - so it is easy to swap for a test double and its lifecycle/scope is configurable. The classic getInstance() form is global static state fetched anywhere, which is hidden and hard to test.
- Why is a stateless singleton far less problematic than a stateful one?With no mutable state there is nothing to leak between callers or tests and no shared-mutable-state concurrency hazard, so the main downsides (test contamination, thread-safety bugs) largely disappear; the remaining concerns are coupling and testability of the static accessor itself.
saying these in an interview costs you the question
- Treating Singleton as a default for every shared service - it is usually a DI/scope concern.
- Claiming singletons have no testing impact - mutable static state leaks between tests and resists mocking.
- Conflating 'I need one instance' with 'I must use the Singleton pattern with static getInstance().'
- Saying DI cannot give you a single instance - container singleton scope does exactly that.