A lot of people (myself included) complain about how verbose Java is. This is especially true when it comes to populating collections from the Java Collection API. Here’s what you typically see:
1 2 3 4 |
List<String> ugh = new ArrayList<String>(); ugh.add("a"); ugh.add("b"); ugh.add("c"); |
It’s frustrating that this is so verbose. Wouldn’t it be better if you could do this common task in a concise way? Well… there is actually a trick you can use in Java to do this. It looks like this:
1 |
List<String> wat = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }}; |
This has exactly the same result, but you should never do this: This is difficult to read and most Java Engineers don’t even know how this works. Then why did I decide to write an article about this if it’s a “worst practice”? Well, it can be fun to know about tricks in Java that others don’t. But more importantly, there is something to learn here. What is this doing? How does it work? We are going to learn that and at the very end I’ll show you what code you should be using instead that’s the best of both worlds.
Before I explain what’s going on here, I’ve got to explain a little known concept called “Instance Initializers”. Did you know you could do this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.sleepeasysoftware.dontdothis; /** * Created by Daniel Kaplan on behalf of Sleep Easy Software. */ public class TheBreakdown { static { System.out.println("I run first"); } public static void main(String[] args) { new TheBreakdown(); } { //This is an Instance Initializer System.out.println("I run second"); } public TheBreakdown() { System.out.println("I run third"); } } |
As you would expect from the way I labeled these String s, this outputs:
1 2 3 |
I run first I run second I run third |
The Instance Initializer gets run before any constructor is run, each time you initialize this class. If you’ve never heard of Instance Initializers, it’s probably because there isn’t much use for them. The most useful thing you can do seems to be that it lets you execute code when an anonymous inner class is created. Anonymous inner classes don’t have names so you can’t define a constructor for them. But you can do this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.sleepeasysoftware.dontdothis; /** * Created by Daniel Kaplan on behalf of Sleep Easy Software. */ public class AnonymousInnerClassInstanceInitializer { public static void main(String[] args) { new InnerClass() { { System.out.println("I am constructing an Anonymous Inner Class Now!"); } }; } static class InnerClass { } } |
I still wouldn’t recommend this, because — like I said — most Java developers won’t understand what’s going on here. Here’s an even trickier example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package com.sleepeasysoftware.dontdothis; /** * Created by Daniel Kaplan on behalf of Sleep Easy Software. */ public class ThisMakesMyBrainHurt { public static void main(String[] args) { new Child(); //this constructor calls Parent() new Child("bye"); //this constructor calls Parent(String) } static class Parent { private String something = null; public Parent() { something = "hi"; } public Parent(String param) { something = param; } public void saySomething() { System.out.println(something); } } static class Child extends Parent { { saySomething(); } public Child() { super(); } public Child(String childParam) { super(childParam); } } } |
The output of this is
1 2 |
hi bye |
This is evidence that the super in the Child Constructor is called, then the Child Instance Initializer, then the rest of the Child Constructor is executed. These are some really esoteric details that you’d probably never run into in real life. So if this part is confusing, I think you can ignore it.
Back to the original example. What is this doing?
1 |
List<String> wat = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }}; |
This is doing a few things:
- It is creating an anonymous inner class that extends ArrayList
- It is defining an Instance Initializer in the anonymous inner class
- In that Instance Initializer, it is calling add three times
The end result is a List with three Strings in it. I hope this was understandable. Please leave me comments if you need clarification on anything.
I promised I would show you a better way to achieve the same examples as above. Here it is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.sleepeasysoftware.dontdothis; import com.google.common.collect.Lists; import java.util.List; /** * Created by Daniel Kaplan on behalf of Sleep Easy Software. */ public class AGreatWayToDoThis { public static void main(String[] args) { List<String> ahhNice = Lists.newArrayList("a", "b", "c"); } } |
That Lists class is part of the Google Guava library, and I highly recommend you use it if you aren’t already.
I hope you learned something interesting in this article. If you’d like to learn more tricks like this, subscribe to my newsletter.