Коллекции
Коллекции позволяют хранить несколько значений одного типа. Отличие от массивов:
- В коллекциях больше возможностей: можно вставлять, удалять элементы и многое другое.
- Хранить можно только значения объектных
типов. Т.е. невозможно создать коллекцию
для типа, например,
int
. Если числа все-таки надо хранить, то храниться они будут в типеInteger
. - Массивы встроены в язык синтаксически (операция взятия индекса с помощью квадратных скобок)
- Массивы часто эффективней коллекций.
Старайтесь не смешивать в программе массивы и коллекции.
Как создать коллекцию?
Коллекции бывают разных видов, самые распространные - это List и Set (списки и множества). Что это значит, см. далее.
List<Integer>
- тип, коллекция, точнее,
список Integer
.
Set<String>
- множество строк.
List<Path>
- список путей к файлам.
Обратим внимание на угловые скобки. В Java
можно написать просто тип List
, но лучше
этого не делать. Всегда в угловых скобках
указывайте, какой тип хранится в списке.
Если вы забудете указать тип в угловых скобках, вы увидите предупреждения “Unchecked cast/…”.
Списки и множества
В списках элементы упорядочены, можно определять, какой элемент первый, второй, какой последний. В множествах не может храниться двух одинаковых элементов. В множествах порядка нет. При переборе множества элементы могут идти в произвольном порядке. Обычно, во множествах хорошо работает операция проверки на принадлежность.
Создание коллекций
- Функция List.of или Set.of
List<Integer> l1 = List.of(1, 2, 3); Set<String> s1 = Set.of("abc", "xy");
они создают коллекцию из указанных элементов. (В Python
l1 = [1, 2, 3]
иs1 = {"abc", "xy"}
).Этот метод создает неизменяемые коллекции, в них невозможно ничего добавить, нельзя ничего удалить.
- Явное создание:
List<Integer> l2 = new ArrayList<Integer>(); Set<String> s2 = new HashSet<String>();
При создании указываем конкретный тип списка или множества, который мы хотим. Бывает ArrayList, LinkedList, …, LinkedHashSet, …
Типы списков и множеств отличаются реализацией, соответственно, скоростью работы.
Как укоротить создание списка:
//можно справа не писать содержимое угловых скобок List<Integer> l2 = new ArrayList<>(); Set<String> s2 = new HashSet<>();
Или
//можно писать var: var l2 = new ArrayList<Integer>(); var s2 = new HashSet<String>();
Действия с коллекциями
действия для любых коллекций
-
l1.add(42)
,s1.add("abc")
- добавить элемент. У списков это добавление в конец. -
l1.addAll(s2)
- добавить в одну коллекцию все элементы другой. -
l1.contains(42)
- проверка, есть ли элемент в коллекции. Для множеств эта операция обычно работает быстро. -
l1.clear()
- очистить. -
l1.remove(42)
- удалить определенный элемент -
Цикл перебора элементов коллекции:
for (int x : l1) System.out.println(x);
Заведена переменная x того же типа, что и содержимое коллекции. Ей последовательно присваиваются все элементы коллекции. Для списка порядок перебора совпадает с порядком элементов.
Для множеств.
- Если это
HashSet
, то порядок перебора произвольный. Это множество надо использовать, если вам нужно просто множество. TreeSet
, то порядок перебора - по возрастанию.LinkedHashSet
, то порядок перебора совпадает с порядком добавления.
- Если это
Действия для Списков
l1.add(1, 42)
Добавить элемент 42 по индексу 1l1.get(1)
Узнать элемент по индекусу 1. (в python:l1[1]
)l1.remove(1)
Удалить элемент по индексу
Ассоциативные массивы, тип Map<K, V>
Соответствует dict в python.
Обычный массив int[] a = {10, 20, 30};
a[ ]
0 -> 10
1 -> 20
2 -> 30
Ассоциативный массив
m[ ]
"cat" -> 3
"dog" -> 3
"rabbit" -> 6
может сопоставлять значениям одного типа значения другого. В примере
ассоциативный массив m
сопоставляет строкам числа.
В python это делается так:
m = {}
m["cat"] = 3
m["dog"] = 3
m["rabbit"] = 6
В Java:
1.
Map<String, Integer> m = Map.of(
"cat", 3,
"dog", 3,
"rabbit", 6
);
обязательно указываем оба типа: тип ключей (String) и тип значений
(Integer). Этим способом нельзя указать больше 10 элементов.\
Получающийся `Map` нельзя изменить
2.
Map<String, Integer> m = new HashMap<>();
m.put("cat", 3);
m.put("dog", 3);
m.put("rabbit", 6);
метод `put` добавляет в ассоциативный массив запись.
`HashMap`, `LinkedHashMap`, `TreeMap` аналогичны соответствующим
множествам в плане того, как они хранят ключи. Т.е. от выбора Map
зависит порядок перебора ключей.
действия над ассоциативными массивами
m.put(key, value)
, соответствуетm[key] = value
.m.get(key)
возвращает значение для данного ключа или null, если ключа нет.m.getOrDefault(key, default)
возвращает значение для ключаkey
, но если его нет, возвращает default.m.containsKey(key)
узнать, содержится ли ключ.m.remove(key)
удалить запись с данным ключом.
Перебор элементов ассоциативного массива
m.keySet()
- множество всех ключейfor (String key : m.keySet()) System.out.println(key + " -> " + m.get(key));
m.values()
- коллекция всех значений 1.m.forEach((key, value) -> { //с отступом в 4 пробела пишем код System.out.println(key + " -> " + value); });
Результат аналогичен первому варианту перебора. Новый синтаксис со стрелочкой, это лямбда выражения, см. след. семестр.
m.entrySet()
- множество записей, пар ключ-значение, тип Map.Entry<String, Integer>.