Коллекции в Java
Аналоги списков (list), множеств (set) в python.
Коллекция в Java — набор из нескольких объектов. В коллекциях пока можно хранить только объектные типы, т.е. коллекцию int пока не сделать.
У коллекции можно узнать размер (метод size()
), ее можно перечислить:
for (String s : коллекция строк) {
действие с элементом коллекции s
}
Еще можно проверить на пустоту (isEmpty()
), добавить или удалить элементы (add()
, remove()
). Есть другие методы
Те виды коллекций, которые нам нужны, можно поделить на два вида:
- списки: хранят порядок элементов
- множества: хранят каждый объект не более 1 раза, обычно еще быстро работает проверка на вхождение элемента в множества
Коллекции описываются классом Collection
, cписки: List
, множества:
класс Set
. Классы коллекций надо указывать с угловыми скобками, в них указывается тип элементов коллекции. Например, List<String>
— это список строк. Set<Integer>
— это множество чисел. (Integer см. позже).
Java разрешает писать без угловых скобок, но это не рекомендуется:
List s = ...
(так не делаем). Их можно не писать только из исторических соображений. Если вы их забудете, получите ошибку или предупреждение о “raw type”.
Примеры:
//создали список из трёх элементов.
List<String> s = List.of("abc", "xyz", "pqr");
//часто можно опускать содержимое угловых скобок, если оно очевидно:
List<> s = List.of("abc", "xyz", "pqr"); //догадается до List<String>
System.out.println(s); // в отличие от массивов распечатка коллекций красивая
//метод contains, общий для всех коллекций:
System.out.println(s.contains("abc")); // true
Самый простой способ создания списка — это List.of()
, но таким образом создаётся неизменяемый список… Любая операция типа add
по добавлению элемента приводит к ошибке времени выполнения.
Чтобы создать свой список, нужен класс ArrayList
, это наследник List
. Это реализация списка с помощью массива. Есть еще LinkedList
, он основан на структуре данных “связанный список”. При создании списка нужно явно указывать, какой список необходим:
//вызов конструктора, создание списка, конкретно ArrayList
List<String> s = new ArrayList<>(); //здесь справа убираем <String>
// List<String> s = new List() — невозможно,
s.add("abc");
s.add("xyz");
s.add("pqr");
System.out.println(s); // список из трех слов
System.out.println(s.size()); // узнаем длину, получаем 3
В списках есть дополнительные методы, которых нет в коллекциях, например, get
:
List<String> s = List.of("abc", "xyz", "pqr");
System.out.println(s.get(0)); // abc
System.out.println(s.get(1)); // xyz
s.remove(1); // удалить элемент по первому индексу
System.out.println(s); // "abc", "pqr"
Создание множества:
//неизменяемое множество
Set<Stirng> set1 = Set.of("abc", "xyz", "pqr");
//изменяемые множества
Set<String> set2 = new HashSet<>();
Set<String> set3 = new LinkedHashSet<>();
Set<String> set4 = new TreeSet<>();
- HashSet — просто множество, порядок произвольный
- LinkedHashSet — множество, которое гарантирует порядок, он совпадает с порядком добавления элементов.
- TreeSet — порядок элементов по возрастанию.
Хранение примитивных типов в коллекциях
Вообще, List<int>
не бывает (пока). У каждого примитивного типа есть класс-обертка:
- int — Integer
- long — Long
- byte — Byte
- short — Short
- boolean — Boolean
- char — Character
- float — Float
- double — Double
Эти типы служат двум целям
- вспомогательные статические функции:
Integer.parseInt("42")
— получаем число int 42. Есть много других.Character.isLowerCase('a')
— проверить, что символ в нижнем регистре. - обертка для значений, чтобы их можно было хранить в коллекциях.
Integer i = new Integer(42); // 42 внутри объекта
System.out.println(i); //42
System.out.println(i.intValue()); //42 как int
Скоро в Java запретят делать new Integer
. На самом деле, в Java работает автоматическое заворачивание (auto boxing) и автоматическое разворачивание (auto unboxing):
Integer i = 1042; // тип справа int, автоматически делает new Integer(1042);. Autoboxing
int ii = i; // содержимое объекта i автоматически достаётся в ii. Autounboxing
Аналогично это работает в коллекциях и везде, где Integer должно превратиться в int и наоборот:
List<Integer> i = List.of(10, 20, 30);
List<Integer> a = new ArrayList<>();
a.add(42); // auto boxing
a.add(123); // auto boxing
int z = a.get(0); //возвращается Integer, auto unboxing
Ожидаются Integer, получены int, они автоматически завернутся в Integer.
Замечание. В явном виде класс Integer и другие классы обертки создаются/используются редко. Обычно только в угловых скобках (типовой параметр).
Замечание о внимательности. Autoboxing всегда отрабатывает без ошибок. А вот autounboxing иногда может завершиться ошибкой. Если значение null, оно не развернется:
Integer z = null;
int a = z; // возникнет ошибка при разворачивании (NullPointerException)
Замечание. Замена элемента в списке:
List<String> s = new ArrayList<>();
s.add("abc");
s.add("xyz");
s.add("pqr");
s.set(1, "xxyyzz"); // заменяем значение по индексу 1
В Python было бы s[1] = "xxyyzz"
.