Удобные фабричные методы Java для коллекций

Опубликовано: 15 Сентября, 2022

В JDK 9 к базовым интерфейсам Collection добавлены статические фабричные методы, такие как of() , для создания неизменяемых объектов коллекций. Это то же самое, что и неизменяемая (неизменяемая) коллекция, которую мы создаем в JDK 6, 7, 8. Она позволяет создавать список, набор и карту значений всего в одной строке. Java 9 не привносит столько кардинальных изменений в наш способ кодирования, как его предшественник, но, несомненно, у нас будут некоторые необычные функции.

Нижеперечисленные пути ведут к создание ненужных объектов. Чтобы преодолеть эту проблему, в Java 9 введены статические фабричные методы для создания неизменяемых списков, наборов и карт, которые будут обсуждаться позже. до этого давайте пересмотрим создание немодифицируемой коллекции до JDK 9 (JDK 7, 8).

Список в JDK 8

List<String> listOfString = new ArrayList<>();
listOfString.add("Geeks");
listOfString.add("Java");
listOfString.add("Kotlin");
listOfString.add("Groovy");
listOfString.add("Scala");
listOfString = Collections.unmodifiableList(listOfString);

Способ 1: использование инициализации с двойными фигурными скобками

List<String> listOfString = Collections.unmodifiableList(new ArrayList<>() {

    {

        add(“Geeks”);

        add(“Java”);

        add(“Kotlin”);

        add(“Groovy”);

        add(“Scala”);

    }

});

Способ 2: использование Arrays API для преобразования массива в ArrayList

List<String> listOfString = Collections.unmodifiableList(Arrays.asList(“Geeks”,”Java”,”Kotlin”,”Groovy”, “Scala”));

Способ 3: использование Stream API

List<String> listOfString = Collections.unmodifiableList(Stream.of(“Bruce”,”Steve”,”Adrian”, “Dave”, “Janick”,”Nicko”).collect(toList()));

Почему Ява 9?

Теперь давайте посмотрим на преимущества, прежде чем использовать статические фабричные методы Java 9, прежде чем переходить к ним.

  • Позволяет создать список, набор и карту значений всего в одну строку.
  • Создание неизменяемых объектов с использованием статических фабричных методов не позволяет нам вставлять пустые значения или дубликаты (в наборы или карты).
  • Мы защищены от получения исключений NullPointerException при обходе элементов коллекции.

Теперь давайте обсудим создание немодифицируемой коллекции в JDK. Здесь list, Set и map обсуждаются ниже.

1. Список в Java 9

List<String> listOfString = List.of("Geeks", "Java", "Kotlin", "Groovy", "Scala");

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

  • List.of() позволяет создать пустой неизменяемый список.
  • Любая модификация вызовет исключение UnsupportedOperationException.
  • Несколько перегруженных версий List.of() доступны с точки зрения производительности.

Неизменяемый список имеет абстрактный базовый класс AbstractImmutableList<E> и четыре реализации:

  • Список0<E>
  • Список1<Е>
  • Список2<Е>
  • СписокN<E>

Каждому из этих типов соответствует количество элементов, которые используются для их создания. В интерфейсе java.util.List у нас есть 12 статических фабричных методов, которые используют приведенные выше реализации для создания неизменяемых объектов:

// creates empty immutable list
static <E> List<E> of()

// creates one-element immutable list
static <E> List<E> of(E e1)

// creates two-element immutable list
static <E> List<E> of(E e1, E e2)

// creates ten-element immutable list
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

// creates N-element immutable list
static <E> List<E> of(E... elements)

Также ускользните от методов, которые выдают UnsupportedOperationException, а именно следующим образом:

  • add(E e), addAll(Collection<? extends E> c), addAll(int index, Collection<? extends E> c)
  • remove(Объект o), removeAll(Collection<?> c), removeIf(Predicate<? super E> filter)
  • replaceAll (оператор UnaryOperator<E>)
  • сохранитьВсе(Коллекция<?> c)
  • sort(Comparator<? super E> c)
  • Чисто()

Вставка значений Null вызовет исключение NullPointerException, как показано ниже.

List<String> listOfString = List.of("Geeks","Java","Kotlin", "Scala", "Groovy", null);
// throws NullPointerException

Следовательно, правильное создание неизменяемого списка выглядит следующим образом:

List<String> listOfString = List.of("Geeks","Java","Kotlin", "Scala", "Groovy","Pearl");

2. Установить в Java 9

  • Set.of() позволяет создать пустой неизменяемый набор.
  • Любая модификация вызовет исключение UnsupportedOperationException.
  • С точки зрения производительности доступно несколько перегруженных версий Set.of() .

Иллюстрация:

Неизменяемый набор реализован аналогично тому, как мы видели это в интерфейсе List. Он имеет абстрактный базовый класс AbstractImmutableSet<E> и четыре реализации:

  • Установить0<E>
  • Набор1<Е>
  • Набор2<Е>
  • ЗадатьN<E>

Это снова соответствует количеству элементов, которые используются при их создании. В интерфейсе java.util.Set у нас есть 12 статических фабричных методов:

// creates empty immutable set
static <E> Set<E> of()

// creates one-element immutable set
static <E> Set<E> of(E e1)

// creates two-element immutable set
static <E> Set<E> of(E e1, E e2)

// creates ten-element immutable set
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

// creates N-element immutable set
static <E> Set<E> of(E... elements)

Методы, вызывающие исключение UnsupportedOperationException, следующие:

  1. добавить(E e), addAll(Collection<? extends E> c)
  2. remove(Объект o), removeAll(Collection<?> c), removeIf(Predicate<? super E> filter)
  3. сохранитьВсе(Коллекция<?> c)
  4. Чисто()

Иллюстрация:

Как и в случае с неизменяемыми списками, мы не можем создать экземпляр Set с нулевым значением, поскольку он выбрасывает исключение NullPointerException, где добавление дубликата приведет к исключению IllegalArgumentException, как показано ниже:

Set<String> setOfString = Set.of("Geeks", "Java", "Kotlin", "Scala", "Groovy", null);
// throws NullPointerException

Set<String> setOfString = Set.of("Geeks", "Java", "Kotlin", "Java");
// throws IllegalArgumentException

Следовательно, допустимое создание неизменяемого набора выглядит следующим образом:

Set<String> setOfString = Set.of("Geeks", "Java", "Kotlin", "Scala", "Groovy", "Pearl");

3. Карта в Java 9

  • Map.of() и Map.ofEntries() позволяют создать неизменяемую карту.
  • Любая модификация вызовет исключение UnsupportedOperationException.
  • Map.of() перегружен для создания карты не более чем из 10 пар ключ-значение.
  • Map.ofEntries() будет использоваться для создания карты из более чем 10 пар ключ-значение.

Неизменная карта имеет абстрактный базовый класс AbstractImmutableMap<K, V> с тремя реализациями:

  • Карта0<К, В>
  • Карта1<К, В>
  • Карта N<K, V>

Снова у нас есть следующий набор фабричных методов внутри интерфейса java.util.Map.

// creates an empty map
static <K, V> Map<K, V> of()

// creates one-element map
static <K, V> Map<K, V> of(K k1, V v1)

// creates two-element map
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)

// creates ten-element map
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4,
                           K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, 
                           K k9, V v9, K k10, V v10)

// creates N-element map
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)

Опять же, методы, вызывающие исключение UnsupportedOperationException, следующие:

  • Чисто()
  • вычислить (клавиша K, BiFunction<? super K,? super V,? extends V> rf)
  • calculateIfAbsent (клавиша K, Function<? super K,? extends V> mf)
  • ComputeIfPresent(Ключ, BiFunction<? super K,? super V,? extends V> rf)
  • слияние (ключ K, значение V, BiFunction<? super V,? super V,? extends V> rf)
  • put(K ключ, значение V), putAll(Map<? расширяет K,? расширяет V> m), putIfAbsent(K ключ, значение V)
  • удалить (ключ объекта), удалить (ключ объекта, значение объекта)
  • заменить (ключ K, значение V), заменить (ключ K, старое значение V, новое значение V), заменить все (BiFunction<? super K,? super V,? extends V> f)

Иллюстрация:

Вставка ключа или значения Null вызовет NullPointerException :

Map<String, Integer> weightInKg = Map.of(null, 59, "John", 61);
// throws NullPointerExcepton because of null key
Map<String, Integer> weightInKg = Map.of("Ron", null, "John", 61);
// throws NullPointerExcepton because of null value
Map<String, Integer> weightInKg = Map.ofEntries(Map.entry("Ron", 59), null);
// throws NullPointerExcepton because of null entry

Добавление повторяющегося ключевого элемента вызовет исключение IllegalArgumentException:

Map<String, Integer> weightInKg = Map.of("Ron", 59, "Ron", 59);
Map<String, Long> weightInKg = Map.ofEntries(Map.entry("Ron", 59), Map.entry("Ron", 59));

Правильное создание неизменяемой карты выглядит следующим образом:

Map<String, Long> weightInKg = Map.of("Ron", 59, "John", 61, "Ed", 60, "Nick", 60, "Jack", 60L, "Ben", 65);
Map<String, Long> age = Map.ofEntries(Map.entry("Ron", 59),
                                      Map.entry("John", 61),
                                      Map.entry("Ed", 60),
                                      Map.entry("Nick", 60),
                                      Map.entry("Jack", 60),
                                      Map.entry("Ben", 65));