Вступление
Фреймворк 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 ()
, мы можем легко добавлять объекты в наш список:
Listproducts = 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 (Iteratoriterator = 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: Установленный Интерфейс .