Java double brace initialization is defined as creating and initializing the objects in a single step, normally done in multiple steps. They are done using double curly braces.
1. Create and Initialize without Double Braces
In Java, every time we have to use a collection (List, Set or Map) in our code, we have to perform the following actions-
- Declare a variable for a temporary collection
- Create a new empty collection and store a reference to it in the variable
- Put things into the collection
- Pass the collection to the method
In the following example, we are creating a Set of Strings and adding 3 string values to the set:
Set<String> params = new HashSet<>();
params.add("one");
params.add("two");
params.add("three");
2. Using Double Brace Initialization
Let us see another easy way of doing it using double braces. The syntax to use the double brace feature is obscure and not easily understood at the first sight:
Set<String> params = new HashSet<String>() {
{
add("one");
add("two");
add("three");
}
};
3. How does Double Brace Initialization Work?
Let us understand how this works. The first brace creates a new anonymous inner class. These inner classes are capable of accessing the behavior of their parent class. So, in our case, we are actually creating a subclass of HashSet
class, so this inner class is capable of using add() method.
And the second set of braces are nothing but instance initializers. If you remind core java concepts, you can easily associate instance initializer blocks with static initializers due to a similar brace-like structure. The only difference is that a static initializer is added with the static keyword and is run only once, no matter how many objects you create.
4. Alternate Approaches
4.1. Java 9 Stream Factory Methods
Java 9 has brought a lot of factory methods that can be used to create and initialize the Java collections in a single statement. It can be an alternative and preferred approach if you are using Java 9 or later. It eliminates the necessity of double brace initialization.
The following is an example of creating the instances of Map, List and Set using the double braces.
List<String> names = List.of("lokesh", "rohit", "alex");
Set<String> names = Set.of("Lokesh", "Amit", "John");
Map<String, String> names = Map.ofEntries(
Map.entry("1", "Lokesh"),
Map.entry("2", "Amit"),
Map.entry("3", "Brian"));
4.2. Java 8 Stream Collectors
Since Java 8, you can find similar use cases in form of Streams API. It provides a number of useful collectors that can collect the Stream elements into a variety of Collection types.
Set<String> names = Stream.of("one", "two", "three").collect(collectingAndThen(toSet(),Collections::unmodifiableSet ));
5. Limitations
- Classes initialized with double braces are basically inner classes. So we can create them for all other classes until they are not
final
. - Such classes should not be used where equals() method is not explicitly modified to use them because mostly
equals()
method checks for class equality also. - You should always keep in mind that initializers are run before constructors (but not before super-class constructors).
- The instance of the anonymous class that you have created contains a synthetic reference to the enclosing object. If you serialize the collection you will also serialize everything in the outer class.
6. Conclusion
In this Java tutorial, we learned to use the double brace initialization and differentiate it from the standard initialization that creates a lot of boilerplate code. We learned the limitations of the double braces and how to use the alternate approaches to have the same result but with more robust code.
Happy Learning !!