Рубрики
Без рубрики

Коллекции Java: Интерфейс Списка

Автор оригинала: Vuk Skobalj.

Вступление

Фреймворк Java Collections – это фундаментальная и необходимая структура, которую любой сильный разработчик Java должен знать как свои пять пальцев.

Коллекция в Java определяется как группа или коллекция отдельных объектов, которые действуют как единый объект.

В Java существует множество классов коллекций , и все они расширяют java.util.Коллекция и java.util.Карта Интерфейсы. Эти классы в основном предлагают различные способы формирования коллекции объектов внутри одного объекта.

Коллекции Java – это платформа, которая обеспечивает множество операций над коллекцией-поиск, сортировку, вставку, манипулирование, удаление и т.д.

Это первая часть серии статей о коллекциях Java:

  • Интерфейс списка (вы находитесь здесь)
  • Установленный Интерфейс
  • Интерфейс Карты
  • Интерфейсы очереди и Deque

Проблемы с массивами

Массивы – это одна из первых вещей, с которыми знакомится новый серверный разработчик Java.

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

И массив, и коллекция являются объектами, представляющими множество других объектов, так зачем же нужны оба?

Давайте рассмотрим коллекцию продуктов:

Product door = new Product("Wooden Door", 35);
Product floorPanel = new Product("Floor Panel", 25);

У нас есть деревянная дверь и дверная панель весом 35 кг и 25 кг соответственно. Это POJOs , что означает, что у них есть только несколько методов получения и установки и метод toString () .

С помощью этого довольно просто создать экземпляр массива этих объектов:

Product[] products = { door, floorPanel };

Печатные Массивы

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

System.out.println(products);

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

com.demo.collections.Product;@14ae5a5

На самом деле нам нужно полагаться на вспомогательный класс java.util.Массивы для получения разумного результата:

System.out.println(Arrays.toString(products));

На этот раз мы видим то, что имеет больше смысла:

[Product{name="Wooden Door", weight=35}, Product{name="Floor Panel", weight=25}]

Добавление и удаление элементов

Наша коллекция продуктов только что увеличилась, и мы должны добавить окно в массив:

final Product window = new Product("Window", 15);
products = add(window, products);
System.out.println(Arrays.toString(products));


public static Object[] add(Object[] array, Object... elements) {
    Object[] tempArray = new Object[array.length + elements.length];
    System.arrayCopy(array, 0, tempArray, 0, array.length);

    for(int i = 0; i < elements.length; i++) {
        tempArray[array.length+i] = elements[i];
        return tempArray;
    }
}

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

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

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

Коллекции

Платформа коллекций Java поставляется вместе с самим JDK. Стоит помнить, что в старые времена, особенно для людей, которые писали C код, разработчикам не предоставляли структуры данных на выбор. На самом деле люди привыкли писать свои собственные структуры данных, что некоторые делают и сегодня.

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

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

Все классы коллекции имеют базовую структуру данных, которую они реализуют – Деревья , Хэш-таблицы , Хэш-карты , Очереди и т. Д. Самостоятельно реализовать эти структуры данных, хотя и потенциально увлекательно, может быть очень сложно – есть много углов, которые вам нужно исправить. Нет необходимости изобретать велосипед, если он уже вам подан, если вы не хотите практиковаться и бросать себе вызов, чтобы придумать инновационные и альтернативные решения.

Мы рассмотрим несколько различных типов коллекций в Java:

  • Списки – Последовательная (упорядоченная) Коллекция. Они отслеживают положение всех элементов, таких как массивы, и предлагают операции поиска, итерации и просмотра диапазона их элементов. Списки могут содержать повторяющиеся элементы.
  • Устанавливает – Применяет ограничения уникальности – не может содержать повторяющиеся элементы. Он не заботится о порядке итераций внутри себя, поскольку моделирует абстракцию математического множества. Наборы не предлагают никаких дополнительных функций, кроме унаследованных от Коллекций .
  • Очереди – Вводят порядок изменений, то есть, если вы добавляете элементы в определенном порядке, вы должны следовать определенному порядку. Очереди предлагают дополнительные операции по вставке, удалению и проверке его элементов. Очереди уникальны тем, что они следуют структуре FIFO (Первый вход, первый выход).
  • Deques – Подобно очередям, двойные очереди (сокращенные до deques) дополнительно предоставляют возможность выполнять операции с элементами с обеих сторон очереди.
  • Карты – Хотя реализации java.util.Map не считаются “истинными коллекциями”, они предлагают операции просмотра коллекций, которые практически позволяют им манипулировать на уровне коллекций. Эта коллекция представляет собой не набор отдельных значений, а пары. Это ассоциации между уникальными ключами и значениями (картами), которые можно найти по этим ключам. Важно отметить, что ключи уникальны, и каждый ключ связан со значением, но значение может быть связано с несколькими ключами.

Коллекция интерфейсов

Как упоминалось выше, все интерфейсы коллекции в Java API расширяют общий интерфейс – java.util.Коллекция . Этот основной интерфейс предоставляет все функции общих коллекций.

Каждый подинтерфейс имеет несколько реализаций, и некоторые из этих подинтерфейсов предлагают дополнительные операции:

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

Наиболее часто используемыми методами в интерфейсе Collection являются:

размер() Получите количество элементов в коллекции
Пусто() True, если размер(), в противном случае false
добавить(элемент) Добавьте элемент в начале этой коллекции
addAll(коллекция) Добавьте все элементы коллекции аргументов в эту коллекцию
удалить(элемент) Удалите элемент из этой коллекции
Удалить все(коллекция) Удалите все элементы коллекции аргументов в эту коллекцию
Сохранить все() Удалите все элементы этой коллекции, не входящие в коллекцию аргументов
содержит(элемент) True, если элемент находится в этой коллекции, в противном случае false
Содержит все(коллекция) Верно, если все элементы коллекции аргументов находятся в этой коллекции
очистить() Удалите все элементы из этой коллекции

Списки

Первый и, вероятно, наиболее часто используемый интерфейс – java.util.Список .

Каждый элемент в списке имеет индекс, значение int , которое определяет их положение. Счетчик индексирования начинается с 0, аналогично индексированию, с которым мы можем столкнуться с массивами.

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Файл java.util.Интерфейс List также добавляет несколько других операций, выходящих за рамки обычных общих операций сбора:

  • получить(индекс int)
  • набор(индекс int, объект object)

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

Добавление элемента

Используя метод add () , мы можем легко добавлять объекты в наш список:

List products = new ArrayList<>();
products.add("Mug");
products.add("Wallet");
products.add("Phone");
System.out.println(products);

Выход:

[Mug, Wallet, Phone]

Примечание : Мы создаем экземпляр списка как его конкретную реализацию ArrayList . В большинстве случаев мы использовали бы эту реализацию для Списка .

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

Интерфейс также предоставляет другую версию метода add () , включая индекс. В этом случае мы добавляем элемент в заданный индекс, и если индекс уже занят другим элементом, все элементы после добавления сдвигаются вправо на единицу:

products.add(2, "Pen");
System.out.println(products);

Выход:

[Mug, Wallet, Pen, Phone]

Извлечение Элементов

Используя метод get() с заданным индексом, мы можем получить определенный элемент в списке:

System.out.println(products.get(0));

Выход:

[Mug]

Удаление Элементов

Используя метод remove () , мы можем удалить элемент из списка. Вызов этого метода вернет элемент, а также сдвинет элементы после него на один индекс назад, чтобы заполнить теперь существующую дыру в последовательности:

System.out.println(products.remove(1));

Выход:

[Wallet]

Элементы Настройки

Используя метод set () , мы можем заменить существующий элемент с заданным индексом:

products.set(1, "Book");

System.out.println(products);

Выход:

[Mug, Book, Phone]

Поиск элементов

Используя метод indexOf () , мы также можем искать значения, заданные индексом. Если поиск завершится неудачно, и ни один объект с заданным индексом не существует, список вернется -1 . В случае нескольких одинаковых объектов список вернет только первый индекс.

Использование lastIndexOf() вернет последний индекс данного элемента.

System.out.println(products.indexOf(5));

Выход:

-1

Повторяющиеся Элементы

Хотя можно выполнять итерацию с для и расширенными циклами-для , интерфейс предоставляет два новых вспомогательных класса, которые позволяют нам выполнять итерацию по спискам – Итератор и Листератор :

for (Iterator iterator = list.iterator(); iterator.hasNext(); ) {
    E element = iterator.next();
    element.someMethod();
    iterator.remove(element);
    //...
}

for (ListIterator iterator = list.listIterator(); iterator.hasNext(); ) {
    E element = iterator.next();
    element.someMethod();
    iterator.remove(element);
    //...
}

Примечание : ListIterator обеспечивает больший контроль над итерацией списка, поскольку позволяет выполнять обход в обоих направлениях, в то время как Итератор разрешает обход только в одном направлении.

Кроме того, Java 8 знакомит нас с действительно простым способом печати элементов с помощью ссылки на метод:

list.forEach(System.out::println);

Реализации и различия

ArrayList : реализует java.util.Список в виде массива с динамическим изменением размера:

  • Хорошая реализация общего назначения
  • Используется по умолчанию
  • Более симпатичный кэш процессора

LinkedList : реализует java.util.Список как двусвязный список:

  • Худшая производительность для многих операций
  • Используйте при добавлении элементов в начале
  • Используйте при добавлении/удалении большого количества

Вообще говоря, ArrayList используется гораздо чаще, чем Связанный список . И процитировать Джошуа Блоха, человека, который написал LinkedList :

“Кто-нибудь на самом деле использует LinkedList? Я написал его и никогда им не пользуюсь.”

Сравнение Производительности

Из-за их различной природы эти реализации имеют разные подходы и время выполнения методов.

В зависимости от требований вам придется выбрать, какой из них использовать. Вообще говоря, из-за своей двусвязной природы LinkedList хорош для частого добавления и удаления, в то время как ArrayList хорош для поиска из-за произвольного доступа.

Вывод

Фреймворк Java Collections – это фундаментальный фреймворк, который каждый разработчик Java должен знать, как использовать.

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

Если вам интересно узнать больше об интерфейсах коллекций, продолжайте читать – Коллекции Java: Установленный Интерфейс .