GitHub 21.5K Star Java engineers become god’s path, not to learn about it!

GitHub 21.5K Star Java engineers become god’s way, really not to learn about it!

Since the Java language’s collection framework (collections, such as list, Map, set, etc.) does not provide any convenient syntactic structures, creating collections of constants is cumbersome. Every time we build it, we do:

Define an empty set class variable. 2. Add elements one by one to the combined class

For example, to pass a Set variable to a method:

Set users = new HashSet();
users.add("Hollis");
users.add("hollis");
users.add("HollisChuang");
users.add("hollis666");
transferUsers(users);
Copy the code

So this is a little bit more complicated, but is there a neat way to do it?

The double parenthesis syntax initializes the collection

Double-brace syntax creates and initializes a new set:

public class DoubleBraceTest { public static void main(String[] args) { Set users = new HashSet() {{ add("Hollis"); add("hollis"); add("HollisChuang"); add("hollis666"); }}; }}Copy the code

Similarly, the syntax for creating and initializing a HashMap is as follows:

Map<String,String> users = new HashMap<>() {{
    put("Hollis","Hollis");
    put("hollis","hollis");
    put("HollisChuang","HollisChuang");
}};
Copy the code

Not only sets and maps, but also collection classes in the JDK can be created and initialized in this way.

When we initialize the collection class with this double parenthesis syntax, we can see a strange thing when compiling the Java file. We can compile DoubleBraceTest using Javac:

javac DoubleBraceTest.java
Copy the code

We’ll find that we get two class files:

DoubleBraceTest.class
DoubleBraceTest$1.class
Copy the code

Experienced friends will probably know as soon as they see these two files that anonymous inner classes must be used.

Yes, the effect of initialization with this double parenthesis is to create anonymous inner classes. The class created has an implicit this pointer to the outer class.

This form is not recommended

First, creating and initializing collections in this form results in many inner classes being created. Because every time you initialize with double curly braces, a new class is generated. Take this example:

Map hollis = new HashMap(){{
    put("firstName", "Hollis");
    put("lastName", "Chuang");
    put("contacts", new HashMap(){{
        put("0", new HashMap(){{
            put("blogs", "http://www.hollischuang.com");
        }});
        put("1", new HashMap(){{
            put("wechat", "hollischuang");
        }});
    }});
}};
Copy the code

This allows many inner classes to be created:

DoubleBraceTest$1$1$1.class
DoubleBraceTest$1$1$2.class
DoubleBraceTest$1$1.class
DoubleBraceTest$1.class
DoubleBraceTest.class
Copy the code

These inner classes are created to be loaded by the class loader, which incurs some extra overhead.

If you use the code above to create and initialize a map in a method and return the map from the method, the method caller may unknowingly hold a resource that cannot be garbage collected.

public Map getMap() {
    Map hollis = new HashMap(){{
        put("firstName", "Hollis");
        put("lastName", "Chuang");
        put("contacts", new HashMap(){{
            put("0", new HashMap(){{
                put("blogs", "http://www.hollischuang.com");
            }});
            put("1", new HashMap(){{
                put("wechat", "hollischuang");
            }});
        }});
    }};

    return hollis;
}
Copy the code

We try to get a map initialized with double parentheses by calling getMap

public class DoubleBraceTest { public static void main(String[] args) { DoubleBraceTest doubleBraceTest = new DoubleBraceTest(); Map map = doubleBraceTest.getMap(); }}Copy the code

The Map returned will now contain a reference to an instance of DoubleBraceTest. The reader can try to verify this fact by debugging or by using the following methods.

Field field = map.getClass().getDeclaredField("this$0");
field.setAccessible(true);
System.out.println(field.get(map).getClass());
Copy the code

alternative

Many people use double parentheses to initialize collections, mainly because it is convenient to initialize collections at the same time as they are defined.

But there are already plenty of solutions that can do this, and you don’t need to use risky solutions.

Use the Arrays utility class

Our Arrays class provides asList to convert an array to a List:

List<String> list2 = Arrays.asList("hollis ", "Hollis", "HollisChuang");
Copy the code

However, it should be noticed that asList is just an inner class of Arrays, which is a view List of the original Arrays. Therefore, an error will be reported if an addition or deletion operation is performed on it.

Use of the Stream

A Stream is a new feature provided in Java that enables intermediate operations such as filtering, sorting, and aggregation of elements within an incoming Stream, and terminal operation to obtain the result of the previous processing.

We can initialize the collection with a Stream:

List<String> list1 = Stream.of("hollis", "Hollis", "HollisChuang").collect(Collectors.toList());
Copy the code

Use third-party utility classes

There are many third-party collection utility classes that can do this, such as Guava, etc. :

ImmutableMap.of("k1", "v1", "k2", "v2");
ImmutableList.of("a", "b", "c", "d");
Copy the code

We’ll talk more about Guava and its definition of immutable sets later

Java 9 built-in methods

In Java 9, there are built-in initialization methods in the List, Map, and other collection classes. For example, the List contains 12 overloaded of methods to do this:

/** * Returns an unmodifiable list containing zero elements. * * See <a href="#unmodifiable">Unmodifiable Lists</a> for details. * * @param <E> the {@code List}'s element type * @return an empty {@code List} * * @since 9 */ static <E> List<E> of() { return ImmutableCollections.emptyList(); } static <E> List<E> of(E e1) { return new ImmutableCollections.List12<>(e1); } static <E> List<E> of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: return ImmutableCollections.emptyList(); case 1: return new ImmutableCollections.List12<>(elements[0]); case 2: return new ImmutableCollections.List12<>(elements[0], elements[1]); default: return new ImmutableCollections.ListN<>(elements); }}Copy the code

About the author: Hollis, a person with a unique pursuit of Coding, is a technical expert of Alibaba, co-author of “Three Courses for Programmers”, and author of a series of articles “Java Engineers becoming Gods”.

Follow the public account [Hollis], the background reply “into god map” can be downloaded to receive the Java engineer advanced mind map.