SlideShare a Scribd company logo
The Singleton
Pattern in Java
1
What is the Singleton Pattern?
• A commonly used idiom to create and maintain objects called
singletons
• A singleton is the only instance of a class
• Common use cases:
• A user’s preferences in a desktop application
• Cache
• Resource pool
2
Example: interface for fetching weather from
an external web service
interface WeatherFetcher {
String fetchWeather(String cityCode) throws IOException;
int fetchTemperature(String cityCode) throws IOException;
}
• Imagine that we are working on a feature which uses this interface
• We need to maintain a connection pool in order to reduce latency
• We want to make sure that we will have only one connection pool, which is
a good use case for the Singleton pattern
3
Singleton which maintains the connection pool
public class SimpleSingleton implements WeatherFetcher {
private static final SimpleSingleton INSTANCE = new SimpleSingleton();
public static WeatherFetcher getInstance() { return INSTANCE; }
private SimpleSingleton() { System.out.println("Populating the connection pool..."); }
@Override public int fetchTemperature(String cityCode) {
// gets an idle connection from the pool, sends a request
return 71; // please assume it's from a response
}
@Override public String fetchWeather(String cityCode) {
// gets an idle connection from the pool, sends a request
return "Sunny"; // please assume it's from a response
}
// client code
public static void main(String[] args) throws IOException {
WeatherFetcher singleton = SimpleSingleton.getInstance();
System.out.printf("Weather in New York: %s, %dFn",
singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork"));
}
} 4
Another requirement: defer initialization until
it’s really necessary
public static void main(String[] args) throws IOException {
System.out.println("Doing some other stuff - I don't need the connection pool yet"); // added
WeatherFetcher singleton = SimpleSingleton.getInstance();
System.out.printf("Weather in New York: %s, %dFn",
singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork"));
}
// The main method yields the following output:
Populating the connection pool...
Doing some other stuff - I don't need the connection pool yet
Weather in New York: Sunny, 71F
• SimpleSingleton’s constructor gets called before the getInstance() call
• Unnecessary resource consumption (initializing the connection pool)
might be imposed on the user 5
Lazy singleton with a static holder class
public class LazySingleton implements WeatherFetcher {
private static class SingletonHolder {
static final LazySingleton INSTANCE = new LazySingleton();
}
public static WeatherFetcher getInstance() { return SingletonHolder.INSTANCE; }
private LazySingleton() { System.out.println("Populating the connection pool..."); }
...
// client code
public static void main(String[] args) throws IOException {
System.out.println("Doing some other stuff - I don't need the connection pool yet");
WeatherFetcher singleton = LazySingleton.getInstance();
System.out.printf("Weather in New York: %s, %dFn",
singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork"));
}
}
// Now the main method yields:
Doing some other stuff - I don't need the connection pool yet
Populating the connection pool...
Weather in New York: Sunny, 71F 6
New requirement: generating a weather report
public class WeatherReporter {
String generateWeatherReport(List<String> cityCodeList) {
StringBuilder sb = new StringBuilder("=== Weather Report ===n");
for (String cityCode : cityCodeList) {
try {
String weather = LazySingleton.getInstance().fetchWeather(cityCode);
int temperature = LazySingleton.getInstance().fetchTemperature(cityCode);
sb.append(String.format("%s: %s, %dFn", cityCode, weather, temperature));
} catch (IOException e) {
sb.append(String.format("%s: Failed to fetch datan", cityCode));
}
}
return sb.toString();
}
}
• Writing unit tests is almost impossible due to static getInstance() calls
• Setting up a data source for testing is too much effort
• Problem: business logic tightly coupled to an external data source
7
Workaround: replacing getInstance() by Supplier
public class ImprovedWeatherReporter {
private final Supplier<? extends WeatherFetcher> weatherFetcherSupplier;
public ImprovedWeatherReporter(Supplier<? extends WeatherFetcher> weatherFetcherSupplier) {
this.weatherFetcherSupplier = weatherFetcherSupplier;
}
String generateWeatherReport(List<String> cityCodeList) {
StringBuilder sb = new StringBuilder("=== Weather Report ===n");
for (String cityCode : cityCodeList) {
try {
String weather = weatherFetcherSupplier.get().fetchWeather(cityCode);
int temperature = weatherFetcherSupplier.get().fetchTemperature(cityCode);
sb.append(String.format("%s: %s, %dFn", cityCode, weather, temperature));
} catch (IOException e) {
sb.append(String.format("%s: Failed to fetch datan", cityCode));
}
}
return sb.toString();
}
}
8
Unit tests for ImprovedWeatherReporter
@ExtendWith(MockitoExtension.class) class ImprovedWeatherReporterTest {
@Mock WeatherFetcher weatherFetcher;
ImprovedWeatherReporter sut;
@BeforeEach void setUp() { sut = new ImprovedWeatherReporter(() -> weatherFetcher); }
@Test void producesReports() throws IOException {
when(weatherFetcher.fetchTemperature("NewYork")).thenReturn(71);
when(weatherFetcher.fetchWeather("NewYork")).thenReturn("Sunny");
when(weatherFetcher.fetchTemperature("Montreal")).thenReturn(68);
when(weatherFetcher.fetchWeather("Montreal")).thenReturn("Cloudy");
String actual = sut.generateWeatherReport(Arrays.asList("NewYork", "Montreal"));
assertThat(actual).isEqualTo("=== Weather Report ===n" +
"NewYork: Sunny, 71Fn" +
"Montreal: Cloudy, 68Fn");
}
@Test void exception() throws IOException {
when(weatherFetcher.fetchTemperature("Tokyo")).thenThrow(new IOException("catch this"));
String actual = sut.generateWeatherReport(Collections.singletonList("Tokyo"));
assertThat(actual).isEqualTo("=== Weather Report ===n" +
"Tokyo: Failed to fetch datan");
}
}
9
Conclusion
• We’ve discussed:
• A couple of common idioms of the Singleton Pattern in Java
• A maintainability issue that can be caused by applying the pattern
• Having getInstance() calls in the middle of business logic can make
code unit test unfriendly
• Introducing a Supplier field instead of getInstance() calls can be a
quick workaround for making code unit test friendly
10

More Related Content

PDF
GPars howto - when to use which concurrency abstraction
PDF
Gpars workshop
ODP
Concurrency on the JVM
PDF
NHibernate Configuration Patterns
PPTX
Reactive Extensions (Rx)
PDF
Przywitaj się z reactive extensions
PDF
Tech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn Tới
PPTX
Flink Batch Processing and Iterations
GPars howto - when to use which concurrency abstraction
Gpars workshop
Concurrency on the JVM
NHibernate Configuration Patterns
Reactive Extensions (Rx)
Przywitaj się z reactive extensions
Tech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn Tới
Flink Batch Processing and Iterations

What's hot (20)

PPTX
Reactive programming with RxAndroid
PPTX
Angular2 rxjs
PDF
Parallel streams in java 8
PPTX
Using Grafana with InfluxDB 2.0 and Flux Lang by Jacob Lisi
PPTX
Reactive Java (33rd Degree)
PDF
Saving lives with rx java
PPTX
PDF
Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...
TXT
New text document
PPTX
Apache Flink Training: DataStream API Part 1 Basic
PPTX
Synapse india dotnet development overloading operater part 4
PPTX
Asynchronous programming
PPTX
No More Deadlocks; Asynchronous Programming in .NET
PDF
Streaming Dataflow with Apache Flink
PPTX
Introduction to rx java for android
PDF
Angular and The Case for RxJS
PPTX
Deep Dumpster Diving
PDF
Ganga: an interface to the LHC computing grid
PPTX
MapReduce wordcount program
PDF
ReactiveCocoa in Practice
Reactive programming with RxAndroid
Angular2 rxjs
Parallel streams in java 8
Using Grafana with InfluxDB 2.0 and Flux Lang by Jacob Lisi
Reactive Java (33rd Degree)
Saving lives with rx java
Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...
New text document
Apache Flink Training: DataStream API Part 1 Basic
Synapse india dotnet development overloading operater part 4
Asynchronous programming
No More Deadlocks; Asynchronous Programming in .NET
Streaming Dataflow with Apache Flink
Introduction to rx java for android
Angular and The Case for RxJS
Deep Dumpster Diving
Ganga: an interface to the LHC computing grid
MapReduce wordcount program
ReactiveCocoa in Practice
Ad

Similar to The Singleton Pattern In Java (20)

PDF
GDG Jakarta Meetup - Streaming Analytics With Apache Beam
PPTX
分散式系統
PPTX
JDBC ResultSet power point presentation by klu
PPTX
Parallel Processing
PDF
Non Blocking I/O for Everyone with RxJava
PDF
Architecture components - IT Talk
PDF
Architecture Components
ODP
Java Concurrency
PDF
Android dev 3
PDF
13multithreaded Programming
DOCX
PPTX
Jdk 7 4-forkjoin
PPTX
Observer & singleton pattern
PDF
Tool Development 07 - Undo & Redo, Drag & Drop
PDF
33rd Degree 2013, Bad Tests, Good Tests
PPTX
Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014
PPTX
Dependency Injection for Android
PDF
Androidの本当にあった怖い話
PDF
Getting started with TDD - Confoo 2014
PDF
12advanced Swing
GDG Jakarta Meetup - Streaming Analytics With Apache Beam
分散式系統
JDBC ResultSet power point presentation by klu
Parallel Processing
Non Blocking I/O for Everyone with RxJava
Architecture components - IT Talk
Architecture Components
Java Concurrency
Android dev 3
13multithreaded Programming
Jdk 7 4-forkjoin
Observer & singleton pattern
Tool Development 07 - Undo & Redo, Drag & Drop
33rd Degree 2013, Bad Tests, Good Tests
Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014
Dependency Injection for Android
Androidの本当にあった怖い話
Getting started with TDD - Confoo 2014
12advanced Swing
Ad

More from Kohei Nozaki (6)

PDF
The State Pattern
PDF
Synchronize access to shared mutable data
PDF
Favor composition over inheritance
PDF
Java Generics wildcards
PDF
JUnit and Mockito tips
PDF
Overview of Java EE
The State Pattern
Synchronize access to shared mutable data
Favor composition over inheritance
Java Generics wildcards
JUnit and Mockito tips
Overview of Java EE

Recently uploaded (20)

PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
AI in Product Development-omnex systems
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
ai tools demonstartion for schools and inter college
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
System and Network Administraation Chapter 3
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
history of c programming in notes for students .pptx
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Adobe Illustrator 28.6 Crack My Vision of Vector Design
AI in Product Development-omnex systems
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
How to Migrate SBCGlobal Email to Yahoo Easily
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
wealthsignaloriginal-com-DS-text-... (1).pdf
ai tools demonstartion for schools and inter college
Wondershare Filmora 15 Crack With Activation Key [2025
Navsoft: AI-Powered Business Solutions & Custom Software Development
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Upgrade and Innovation Strategies for SAP ERP Customers
Design an Analysis of Algorithms II-SECS-1021-03
System and Network Administraation Chapter 3
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Reimagine Home Health with the Power of Agentic AI​
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
2025 Textile ERP Trends: SAP, Odoo & Oracle
CHAPTER 2 - PM Management and IT Context
history of c programming in notes for students .pptx

The Singleton Pattern In Java

  • 2. What is the Singleton Pattern? • A commonly used idiom to create and maintain objects called singletons • A singleton is the only instance of a class • Common use cases: • A user’s preferences in a desktop application • Cache • Resource pool 2
  • 3. Example: interface for fetching weather from an external web service interface WeatherFetcher { String fetchWeather(String cityCode) throws IOException; int fetchTemperature(String cityCode) throws IOException; } • Imagine that we are working on a feature which uses this interface • We need to maintain a connection pool in order to reduce latency • We want to make sure that we will have only one connection pool, which is a good use case for the Singleton pattern 3
  • 4. Singleton which maintains the connection pool public class SimpleSingleton implements WeatherFetcher { private static final SimpleSingleton INSTANCE = new SimpleSingleton(); public static WeatherFetcher getInstance() { return INSTANCE; } private SimpleSingleton() { System.out.println("Populating the connection pool..."); } @Override public int fetchTemperature(String cityCode) { // gets an idle connection from the pool, sends a request return 71; // please assume it's from a response } @Override public String fetchWeather(String cityCode) { // gets an idle connection from the pool, sends a request return "Sunny"; // please assume it's from a response } // client code public static void main(String[] args) throws IOException { WeatherFetcher singleton = SimpleSingleton.getInstance(); System.out.printf("Weather in New York: %s, %dFn", singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork")); } } 4
  • 5. Another requirement: defer initialization until it’s really necessary public static void main(String[] args) throws IOException { System.out.println("Doing some other stuff - I don't need the connection pool yet"); // added WeatherFetcher singleton = SimpleSingleton.getInstance(); System.out.printf("Weather in New York: %s, %dFn", singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork")); } // The main method yields the following output: Populating the connection pool... Doing some other stuff - I don't need the connection pool yet Weather in New York: Sunny, 71F • SimpleSingleton’s constructor gets called before the getInstance() call • Unnecessary resource consumption (initializing the connection pool) might be imposed on the user 5
  • 6. Lazy singleton with a static holder class public class LazySingleton implements WeatherFetcher { private static class SingletonHolder { static final LazySingleton INSTANCE = new LazySingleton(); } public static WeatherFetcher getInstance() { return SingletonHolder.INSTANCE; } private LazySingleton() { System.out.println("Populating the connection pool..."); } ... // client code public static void main(String[] args) throws IOException { System.out.println("Doing some other stuff - I don't need the connection pool yet"); WeatherFetcher singleton = LazySingleton.getInstance(); System.out.printf("Weather in New York: %s, %dFn", singleton.fetchWeather("NewYork"), singleton.fetchTemperature("NewYork")); } } // Now the main method yields: Doing some other stuff - I don't need the connection pool yet Populating the connection pool... Weather in New York: Sunny, 71F 6
  • 7. New requirement: generating a weather report public class WeatherReporter { String generateWeatherReport(List<String> cityCodeList) { StringBuilder sb = new StringBuilder("=== Weather Report ===n"); for (String cityCode : cityCodeList) { try { String weather = LazySingleton.getInstance().fetchWeather(cityCode); int temperature = LazySingleton.getInstance().fetchTemperature(cityCode); sb.append(String.format("%s: %s, %dFn", cityCode, weather, temperature)); } catch (IOException e) { sb.append(String.format("%s: Failed to fetch datan", cityCode)); } } return sb.toString(); } } • Writing unit tests is almost impossible due to static getInstance() calls • Setting up a data source for testing is too much effort • Problem: business logic tightly coupled to an external data source 7
  • 8. Workaround: replacing getInstance() by Supplier public class ImprovedWeatherReporter { private final Supplier<? extends WeatherFetcher> weatherFetcherSupplier; public ImprovedWeatherReporter(Supplier<? extends WeatherFetcher> weatherFetcherSupplier) { this.weatherFetcherSupplier = weatherFetcherSupplier; } String generateWeatherReport(List<String> cityCodeList) { StringBuilder sb = new StringBuilder("=== Weather Report ===n"); for (String cityCode : cityCodeList) { try { String weather = weatherFetcherSupplier.get().fetchWeather(cityCode); int temperature = weatherFetcherSupplier.get().fetchTemperature(cityCode); sb.append(String.format("%s: %s, %dFn", cityCode, weather, temperature)); } catch (IOException e) { sb.append(String.format("%s: Failed to fetch datan", cityCode)); } } return sb.toString(); } } 8
  • 9. Unit tests for ImprovedWeatherReporter @ExtendWith(MockitoExtension.class) class ImprovedWeatherReporterTest { @Mock WeatherFetcher weatherFetcher; ImprovedWeatherReporter sut; @BeforeEach void setUp() { sut = new ImprovedWeatherReporter(() -> weatherFetcher); } @Test void producesReports() throws IOException { when(weatherFetcher.fetchTemperature("NewYork")).thenReturn(71); when(weatherFetcher.fetchWeather("NewYork")).thenReturn("Sunny"); when(weatherFetcher.fetchTemperature("Montreal")).thenReturn(68); when(weatherFetcher.fetchWeather("Montreal")).thenReturn("Cloudy"); String actual = sut.generateWeatherReport(Arrays.asList("NewYork", "Montreal")); assertThat(actual).isEqualTo("=== Weather Report ===n" + "NewYork: Sunny, 71Fn" + "Montreal: Cloudy, 68Fn"); } @Test void exception() throws IOException { when(weatherFetcher.fetchTemperature("Tokyo")).thenThrow(new IOException("catch this")); String actual = sut.generateWeatherReport(Collections.singletonList("Tokyo")); assertThat(actual).isEqualTo("=== Weather Report ===n" + "Tokyo: Failed to fetch datan"); } } 9
  • 10. Conclusion • We’ve discussed: • A couple of common idioms of the Singleton Pattern in Java • A maintainability issue that can be caused by applying the pattern • Having getInstance() calls in the middle of business logic can make code unit test unfriendly • Introducing a Supplier field instead of getInstance() calls can be a quick workaround for making code unit test friendly 10