loading...

Effective Java Tuesday! Singletons!

kylec32 profile image Kyle Carter ・3 min read

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Time for chapter three of our Effective Java review. Today's is a fairly simple one. Today we are talking about the singleton pattern. The singleton pattern is quite well known and basically comes down to an object that only allows instantiation once.

So what benefits does a singleton give us?

  • Expensive objects can be avoided being generated multiple times.
  • If there is a reason we shouldn't have an unbounded amount of objects we can own instance control.

What about some cons:

  • They are extremely hard to test (having your singleton implement an interface can help this some)
  • They basically serve as global state that can be complex and cause bugs.

So a singleton is definitely not without it's costs but let's say we have determined that we do need a singleton, what are our options of implementing the pattern? Well Effective Java goes through three methods all including hiding the constructor of the object in one way or another.

Option 1: public constant field

The first option that is described is quite simple. The first step is to create a private constructor. After that you simply create a public static final field that instantiates the object to be used. Let's look at an example:

public class CEO {
  public static final INSTANCE = new CEO();
  private CEO() { }
  public void fire(Employee slacker) { ... }
}

So in this example we want to make sure that we don't end up with more than one CEO and so we make a singleton out of class. Then when a user wants to gain access to the CEO they simple call CEO.INSTANCE. This method is definitely very easy to write and very easy to use. The downsides are that users can get around the single instance protection by using some reflection skills. It also doesn't give as much control over instance creation and going back on the singleton choice.

Option 2: getInstance factory method

The second option is what I am most familiar with. This method is built around having a static factory getInstance factory method method that provides the single instance of the class. Example time:


public class CEO {
  private static final INSTANCE = new CEO();
  private CEO() { }
  public static CEO getInstance() {
    return INSTANCE;
  }
  public void fire(Employee slacker) { ... }
}

So what benefits do we get here? Well for one it's very recognizable as a singleton so the user can easily see what they are interacting with. It also allows us more control over our instance creation. For example we can delay instantiation of the object until it's first needed.

public CEO {
  private static final INSTANCE;
  public static synchronized CEO getInstance() {
     if(INSTANCE == null) {
        INSTANCE = new CEO();
     }
     return INSTANCE;
  }
}

With a pattern like this you need to be careful about race conditions though. It is of note that this pattern is still susceptible to reflection attacks. Effective Java also goes into how to handle serialization as it relates to singletons and is not extremely straightforward. I've never had to deal with that so I won't tackle it here but if you need to go look it up.

Option 3: Single Element Enum

The final option is to create a single element enum. This was not an option that I had ever seen and it does still feel a little unnatural to me. So let's look at an example:

public enum CEO {
  INSTANCE;

  public void fire(Employee slacker) { ... }
}

So what does this give us? Well it is simple to write. Probably the least code of the three options. It also is very safe. It doesn't leave the option for reflection attacks. It also handles the serialization complexities that I skipped above. It does make it so you can't extend from a class but you can still implement interfaces. Effective Java pitches that this is the option that most people should take. Given that I have never personally seen someone use this method it's quite interesting to me that it is pitched as the option most should take.

How about you? Have you ever seen this method used?

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Posted on by:

kylec32 profile

Kyle Carter

@kylec32

Backend Architect at MasterControl

Discussion

markdown guide
 

I know I'm late to the party, but I wonder why you would ever use the Singleton pattern instead of just a static class. Doesn't it achieve exactly the same?

 

I'm not sure I'm following what you mean by "static class." The only static classes come to mind are static inner classes (dev.to/kylec32/effective-java-favo...) which don't solve the singleton problem but instead allows access to a nested class without having a handle on the outer class. Still useful, just not for this problem. Maybe I'm just misunderstanding the question thought.

 

Thank you for your response. I guess I didn't explain very well. What I mean is a class where the members and methods are static. This way you can call the static method of the class to do what you want instead of creating an object. eg: ClassName.staticMethod()

Thanks for that clarification. Yeah I don't see any problem with that. It seems like just a slight change from option 1. Potentially the downside I see is you don't keep the option of changing how it gets initialized in the future. If that's not needed then you likely are good with this option.

 

What about storing the singleton value in a static nested class?

 

Interesting. I see no reason that you couldn't do that if it made sense to put the singleton in such a nested class. Something to keep in mind if the option ever comes up.

 

I thought that was the official way to create lazy singletons without synchronization.

public class CEO {
  private CEO() { }

  public static CEO getInstance() {
    return InstanceHolder.instance;
  }

  public void fire(Employee slacker) { ... }

  private static final class InstanceHolder {
    private static final CEO instance = new CEO();
  }
}

Will you look at that! Still never seen that but you are 100% correct this would allow lazy initialization without synchronization. Thanks for educating me about that.

 

"They are extremely hard to test" - why?

 

A fair question indeed, and one that I did not demonstrate above in my examples. Since the constructor is not accessible to us, even in a test, we are unable to change how the object is created and can't get the benefit of dependency injection (dev.to/kylec32/effective-java-tues...). While none of the above examples show any places where that would be a problem, many singletons in the wild do have this problem if they have any external dependencies (DB, network, other components, etc). So the more I think of it, it's likely the lack of ability to use dependency injection that is the true problem here.

Compare that to a singleton that is just a collection of pure functions that would indeed be testable (but at that point you are more looking at a Utility class dev.to/kylec32/effective-java-tues...)

 

I think you're right about Dependency Injection for unit testing with only, say, JUnit 5.

However, this is where I have found mocking libraries such as Mockito benefit the tests, as the coupled logic can be stubbed out.

(Thanks for the detailed reply πŸ‘ )

Edit: Your second link doesn't appear to be working?

 

Per Effective Java - we get the serialization machinery free.