Никогда больше не создавайте такие коллекции! Очень легко потерять память!

задняя часть

Путь Java-инженера с 21,5 тысячами звезд GitHub к тому, чтобы стать богом, почему бы вам не прийти и не узнать об этом!

Путь Java-инженера с 21,5 тысячами звезд GitHub к тому, чтобы стать богом, разве вы не хотите узнать об этом!

Поскольку структура коллекций языка Java (коллекции, такие как список, карта, набор и т. д.) не предоставляет какой-либо удобной синтаксической структуры, это сильно усложняет работу по созданию коллекций констант. Каждый раз, когда мы строим, мы делаем:

1. Определите пустую переменную класса коллекции 2. Добавляйте элементы в этот комбинированный класс один за другим 3. Передать коллекцию в качестве параметра метода

Например, чтобы передать переменную Set методу:

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

Этот способ написания немного сложен. Есть ли краткий способ?

Сборник инициализации синхронизации бренда

На самом деле есть относительно простой способ, т.синтаксис двойной скобки(double-brace syntax) для создания и инициализации новой коллекции:

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

Точно так же синтаксис для создания и инициализации HashMap выглядит следующим образом:

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

Таким образом можно создавать и инициализировать не только Set и Map, но и классы коллекций в jdk.

Когда мы используем этот синтаксис с двойными скобками для инициализации класса коллекции, когда файлы Java компилируются, вы можете обнаружить странное явление, используйте javac для компиляции DoubleBraceTest:

javac DoubleBraceTest.java

Мы обнаружим, что получаем два файла классов:

DoubleBraceTest.class
DoubleBraceTest$1.class

Опытные друзья могут знать, что когда они видят эти два файла, необходимо использовать анонимные внутренние классы.

Правильно, результатом использования этой инициализации с двойными скобками является создание анонимного внутреннего класса. Созданный класс имеет неявный указатель this на внешний класс.

Эта форма не рекомендуется

Во-первых, создание и инициализация коллекций в этой форме приводит к созданию множества внутренних классов. Потому что каждый раз, когда вы инициализируете двойными фигурными скобками, создается новый класс. Как в этом примере:

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");
        }});
    }});
}};

Это приведет к созданию множества внутренних классов:

DoubleBraceTest$1$1$1.class
DoubleBraceTest$1$1$2.class
DoubleBraceTest$1$1.class
DoubleBraceTest$1.class
DoubleBraceTest.class

Эти внутренние классы создаются и должны быть загружены классовым погрузчиком, который приносит некоторые дополнительные накладные расходы.

Если вы используете приведенный выше код для создания и инициализации карты в методе и возвращаете эту карту из метода, вызывающая сторона метода может неосознанно удерживать ресурс, который не может быть удален сборщиком мусора.

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;
}

Мы пытаемся инициализировать такую ​​карту двойными скобками, вызывая getMap

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

Возвращенная карта теперь будет содержать ссылку на экземпляр DoubleBraceTest. Читатели могут попробовать подтвердить этот факт с помощью отладки или следующим образом.

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

альтернативный план

Многие люди используют двойные скобки для инициализации коллекций, в основном потому, что удобнее инициализировать коллекции при их определении.

Но на самом деле схем для этого уже много, и нет необходимости использовать эту рискованную схему.

Использование служебного класса Arrays

Когда мы хотим инициализировать список, вы можете помочь классу Arrays, Arrays предоставляет asList, который можно преобразовать в список массивов:

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

Однако следует отметить, что ASLIST получает только внутренний класс Arrays, который представляет собой список просмотра массива, поэтому, если вы добавите в него ошибку, вы сообщите об ошибке.

Использовать поток

Поток — это новая функция, представленная в Java, которая может выполнять промежуточные операции (промежуточные операции), такие как фильтрация, сортировка и агрегирование элементов внутри входящего потока, и, наконец, получать результат предыдущей обработки терминальной операцией.

Мы можем инициализировать коллекцию с помощью Stream:

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

Используйте сторонние инструменты

Многие сторонние классы инструментов для сбора данных могут реализовать эту функцию, например, Guava и т. д.:

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

О гуаве и определенных в ней неизменяемых коллекциях мы подробно расскажем позже.

Встроенные методы Java 9

Фактически, в Java 9 методы инициализации были встроены в классы коллекций, такие как List и Map, например, List содержит 12 перегруженных методов, которые используются для этого:

/**
 * 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);
    }
}

Об авторе:Hollis, человек с уникальным увлечением программированием, технический эксперт Alibaba, соавтор «Трех курсов для программистов» и автор серии статей «Дорога к Java-инженерам».

Обратите внимание на общедоступный номер【Hollis], фоновый ответ «Карта Бога» может получить расширенную карту разума инженеров Java.