Урок 6: Коллекции Java – как хранить много данных разом
Привет, юный программист! На прошлых уроках мы научились создавать переменные и массивы. Но что если нам нужно хранить не 10 или 20 элементов, а сотни или тысячи? Или если мы не знаем заранее, сколько данных понадобится? Или нужно быстро найти, удалить или отсортировать данные?
Представь, что ты собираешь коллекцию LEGO. У тебя есть коробка (массив), в которой строго 100 ячеек. Но вдруг тебе подарили 101-й кирпичик – и он уже не помещается! Или ты хочешь найти все красные кирпичи – придется перебирать всю коробку.
В Java для таких задач существуют Коллекции – это как супер-коробки, которые сами умеют расширяться, сжиматься, сортироваться и искать элементы.
Что такое коллекции и зачем они нужны?
Коллекция – это объект, который хранит группу других объектов. Главное отличие от массива:
- Массив – фиксированный размер (как гараж на 10 машин).
- Коллекция – динамический размер (как парковка, которая может расширяться).
Представь, что ты ведешь список друзей в телефоне. Сначала их 5, потом 10, потом 50. Коллекция позволяет добавлять и удалять контакты без проблем.
Основные виды коллекций в Java (из пакета java.util):
- List – список, где важен порядок (как список покупок).
- Set – множество, где каждый элемент уникален (как коллекция марок – две одинаковые не нужны).
- Map – словарь, где есть ключ и значение (как телефонная книга: имя → номер).
Сегодня мы подробно разберем List и его главную реализацию – ArrayList. Это самая популярная коллекция в Java!
ArrayList – эластичный массив
ArrayList – это как массив, но который может сам увеличиваться. Внутри он хранит обычный массив, но когда места не хватает, создает новый, большего размера, и копирует туда все элементы.
Давай создадим наш первый ArrayList:
import java.util.ArrayList; // 1. Подключаем класс ArrayList
public class Main {
public static void main(String[] args) {
// 2. Создаем список строк
ArrayList<String> списокДрузей = new ArrayList<>();
// 3. Добавляем элементы
списокДрузей.add("Анна"); // Добавили Анну
списокДрузей.add("Борис"); // Добавили Бориса
списокДрузей.add("Вика"); // Добавили Вику
// 4. Выводим на экран
System.out.println("Мои друзья: " + списокДрузей);
// Вывод: [Анна, Борис, Вика]
}
}
Обрати внимание на <String> – это дженерик, он говорит, что список будет хранить только строки. Если попробуешь добавить число – Java выдаст ошибку на этапе компиляции.
Основные операции с ArrayList
Давай рассмотрим самые частые действия, которые можно делать со списком:
import java.util.ArrayList;
public class ПримерСписка {
public static void main(String[] args) {
ArrayList<Integer> оценки = new ArrayList<>();
// add() – добавляет элемент в конец
оценки.add(5); // [5]
оценки.add(4); // [5, 4]
оценки.add(3); // [5, 4, 3]
// add(index, element) – вставляет на определенную позицию
оценки.add(1, 2); // [5, 2, 4, 3] – вставили 2 на место с индексом 1
// get(index) – получает элемент по индексу
int перваяОценка = оценки.get(0); // 5
System.out.println("Первая оценка: " + перваяОценка);
// set(index, element) – заменяет элемент
оценки.set(2, 5); // [5, 2, 5, 3] – исправили 4 на 5
// remove(index) – удаляет элемент по индексу
оценки.remove(1); // [5, 5, 3] – удалили двойку
// size() – возвращает количество элементов
int количество = оценки.size(); // 3
System.out.println("Оценок в журнале: " + количество);
// contains(element) – проверяет, есть ли элемент
boolean естьПятерка = оценки.contains(5); // true
System.out.println("Есть ли пятерка? " + естьПятерка);
// indexOf(element) – ищет индекс элемента
int индекс = оценки.indexOf(3); // 2 (индекс тройки)
// clear() – очищает весь список
// оценки.clear(); // убрали бы все оценки
System.out.println("Итоговый список: " + оценки);
}
}
Важно: Индексы в ArrayList начинаются с 0, как и в массивах. Первый элемент имеет индекс 0, второй – 1 и так далее.
Перебор элементов списка
Когда у тебя много элементов, их нужно перебрать. Есть три основных способа:
Способ 1: Цикл for по индексу (как с массивом)
ArrayList<String> имена = new ArrayList<>();
имена.add("Оля");
имена.add("Петя");
имена.add("Саша");
for (int i = 0; i < имена.size(); i++) {
String имя = имена.get(i);
System.out.println("Привет, " + имя + "!");
}
Способ 2: Цикл for-each (более современный)
for (String имя : имена) {
System.out.println("Привет, " + имя + "!");
}
Этот способ короче и понятнее. Он перебирает каждый элемент автоматически.
Способ 3: Метод forEach (с лямбда-выражением)
имена.forEach(имя -> System.out.println("Привет, " + имя + "!"));
Этот способ самый современный, но требует понимания лямбда-выражений. Пока используй первые два.
Практический пример: список покупок
Давай создадим программу для управления списком покупок:
import java.util.ArrayList;
import java.util.Scanner;
public class СписокПокупок {
public static void main(String[] args) {
ArrayList<String> покупки = new ArrayList<>();
Scanner сканер = new Scanner(System.in);
while (true) {
System.out.println("\n=== Меню ===");
System.out.println("1. Добавить товар");
System.out.println("2. Удалить товар");
System.out.println("3. Показать список");
System.out.println("4. Выйти");
System.out.print("Выбери действие: ");
int выбор = сканер.nextInt();
сканер.nextLine(); // очищаем буфер после числа
if (выбор == 1) {
System.out.print("Введи название товара: ");
String товар = сканер.nextLine();
покупки.add(товар);
System.out.println("Товар \"" + товар + "\" добавлен!");
} else if (выбор == 2) {
System.out.print("Введи номер товара для удаления: ");
int номер = сканер.nextInt();
if (номер >= 0 && номер < покупки.size()) {
String удаленный = покупки.remove(номер);
System.out.println("Удален товар: " + удаленный);
} else {
System.out.println("Неверный номер!");
}
} else if (выбор == 3) {
System.out.println("Твой список покупок:");
if (покупки.isEmpty()) {
System.out.println("Список пуст!");
} else {
for (int i = 0; i < покупки.size(); i++) {
System.out.println((i + 1) + ". " + покупки.get(i));
}
}
} else if (выбор == 4) {
System.out.println("Пока!");
break;
} else {
System.out.println("Неверный выбор!");
}
}
сканер.close();
}
}
Эта программа позволяет добавлять товары, удалять их по номеру и просматривать весь список. Протестируй её в своей среде разработки!
ArrayList с числами и другими типами
ArrayList может хранить любые объекты. Но с числами есть нюанс: мы не можем написать ArrayList<int>, потому что int – примитивный тип. Используем классы-обертки:
ArrayList<Integer> числа = new ArrayList<>(); // Integer – обертка для int
ArrayList<Double> дроби = new ArrayList<>(); // Double – обертка для double
ArrayList<Boolean> флаги = new ArrayList<>(); // Boolean – обертка для boolean
Java сама умеет преобразовывать int в Integer (это называется автоупаковка):
ArrayList<Integer> числа = new ArrayList<>();
числа.add(5); // int 5 автоматически становится Integer 5
int x = числа.get(0); // Integer автоматически становится int
Сравнение ArrayList и массива
| Характеристика | Массив | ArrayList |
|---|---|---|
| Размер | Фиксированный | Динамический |
| Скорость доступа | Очень быстрый | Быстрый |
| Добавление в конец | Нельзя | Быстро |
| Добавление в середину | Сложно | Медленно |
| Удаление | Сложно | Просто |
| Поиск элемента | Ручной перебор | Есть методы (contains, indexOf) |
Когда использовать массив? Если размер известен и не меняется, и нужна максимальная скорость. Во всех остальных случаях – ArrayList удобнее.
Другие полезные методы ArrayList
import java.util.ArrayList;
import java.util.Collections; // для сортировки
public class ПолезныеМетоды {
public static void main(String[] args) {
ArrayList<Integer> числа = new ArrayList<>();
числа.add(7);
числа.add(3);
числа.add(9);
числа.add(1);
// isEmpty() – проверяет, пуст ли список
System.out.println("Список пуст? " + числа.isEmpty()); // false
// containsAll() – проверяет, содержит ли список все элементы другой коллекции
ArrayList<Integer> подмножество = new ArrayList<>();
подмножество.add(3);
подмножество.add(7);
System.out.println("Содержит 3 и 7? " + числа.containsAll(подмножество)); // true
// removeAll() – удаляет все элементы, которые есть в другой коллекции
ArrayList<Integer> дляУдаления = new ArrayList<>();
дляУдаления.add(1);
дляУдаления.add(9);
числа.removeAll(дляУдаления);
System.out.println("После удаления 1 и 9: " + числа); // [7, 3]
// retainAll() – оставляет только те, что есть в другой коллекции
ArrayList<Integer> дляСохранения = new ArrayList<>();
дляСохранения.add(7);
числа.retainAll(дляСохранения);
System.out.println("Оставили только 7: " + числа); // [7]
// Сортировка с помощью Collections
числа.add(5);
числа.add(2);
числа.add(8);
Collections.sort(числа); // сортируем по возрастанию
System.out.println("Отсортировано: " + числа); // [2, 5, 7, 8]
// toArray() – преобразует список в массив
Integer[] массив = числа.toArray(new Integer[0]);
System.out.println("Первый элемент массива: " + массив[0]);
// subList() – получает часть списка (срез)
ArrayList<Integer> часть = new ArrayList<>(числа.subList(1, 3));
System.out.println("Элементы с 1 по 3 (не включая 3): " + часть); // [5, 7]
}
}
Практический пример: Студенческий журнал
Давай напишем программу, которая хранит оценки студентов и умеет вычислять средний балл:
import java.util.ArrayList;
import java.util.Scanner;
public class ЖурналОценок {
public static void main(String[] args) {
ArrayList<Integer> журнал = new ArrayList<>();
Scanner сканер = new Scanner(System.in);
System.out.println("Вводи оценки (от 2 до 5). Для завершения введи 0:");
// Ввод оценок
while (true) {
System.out.print("Оценка: ");
int оценка = сканер.nextInt();
if (оценка == 0) break;
if (оценка >= 2 && оценка <= 5) {
журнал.add(оценка);
} else {
System.out.println("Оценка должна быть от 2 до 5!");
}
}
if (журнал.isEmpty()) {
System.out.println("Нет ни одной оценки!");
return;
}
// Вывод всех оценок
System.out.println("\nВсе оценки:");
for (int i = 0; i < журнал.size(); i++) {
System.out.print(журнал.get(i) + " ");
}
System.out.println();
// Вычисление среднего балла
int сумма = 0;
for (int оценка : журнал) {
сумма += оценка;
}
double среднийБалл = (double) сумма / журнал.size();
System.out.printf("Средний балл: %.2f\n", среднийБалл);
// Подсчет отличных и хороших оценок
int отлично = 0;
int хорошо = 0;
for (int оценка : журнал) {
if (оценка == 5) отлично++;
else if (оценка == 4) хорошо++;
}
System.out.println("Пятерок: " + отлично);
System.out.println("Четверок: " + хорошо);
System.out.println("Всего оценок: " + журнал.size());
сканер.close();
}
}
Как работает ArrayList внутри?
Понимание внутреннего устройства поможет тебе писать эффективный код. ArrayList внутри содержит обычный массив. Когда ты создаешь объект:
ArrayList<String> список = new ArrayList<>(); // начальная емкость = 10
Создается массив на 10 элементов. Когда ты добавляешь 11-й элемент:
- Создается новый массив большего размера (обычно в 1.5 раза больше).
- Все старые элементы копируются в новый массив.
- Старый массив удаляется сборщиком мусора.
Это занимает время, поэтому если заранее знаешь, что будет много элементов, можно задать начальную емкость:
ArrayList<String> большойСписок = new ArrayList<>(1000); // сразу выделяем место под 1000 элементов
Ошибки, которых стоит избегать
Вот типичные ошибки новичков при работе с ArrayList:
// Ошибка 1: Выход за границы
ArrayList<String> список = new ArrayList<>();
список.add("A");
// список.get(5); // ОШИБКА! IndexOutOfBoundsException – в списке только 1 элемент
// Ошибка 2: Забыли импортировать
// import java.util.ArrayList; // если не написать эту строку, будет ошибка компиляции
// Ошибка 3: Путаница с remove
ArrayList<Integer> числа = new ArrayList<>();
числа.add(10);
числа.add(20);
числа.add(30);
числа.remove(1); // удаляет элемент с индексом 1 (число 20), а не число 1!
System.out.println(числа); // [10, 30]
// Ошибка 4: Изменение списка во время перебора
for (int i = 0; i < числа.size(); i++) {
if (числа.get(i) == 10) {
числа.remove(i); // так делать можно, но нужно быть осторожным с индексами
}
}
// Лучше использовать итератор или копию списка
Заключение
Сегодня мы научились работать с ArrayList – самой популярной коллекцией в Java. Ты узнал:
- Как создавать списки и добавлять элементы
- Как получать, изменять и удалять элементы по индексу
- Как перебирать списки разными способами
- Как сортировать и искать элементы
- Как использовать ArrayList с числами и строками
ArrayList – это твой верный помощник, когда нужно хранить много данных, размер которых может меняться. На следующем уроке мы познакомимся с другими коллекциями: HashSet и HashMap.
А теперь – практические задания, чтобы закрепить материал!
Практические задания
Задание 1: Список дел
Создай программу, которая управляет списком дел на день. Программа должна:
- Позволять добавлять дела (ввод с клавиатуры)
- Показывать все дела с номерами
- Позволять отмечать дело как выполненное (удалять его из списка)
- Показывать количество оставшихся дел
- Выходить по команде "выход"
Подсказка: используй бесконечный цикл while(true) и проверяй ввод через equals().
Задание 2: Анализ чисел
Напиши программу, которая:
- Запрашивает у пользователя 10 целых чисел
- Сохраняет их в ArrayList
- Находит и выводит минимальное и максимальное число
- Выводит сумму всех чисел
- Выводит среднее арифметическое
- Выводит все четные числа из списка
Подсказка: для поиска минимума и максимума используй Collections.min() и Collections.max().
Задание 3: Умный список контактов
Создай программу-телефонную книгу. У каждого контакта есть имя (строка) и номер телефона (строка). Используй два ArrayList: один для имен, другой для номеров, где индексы совпадают (имя[0] и номер[0] – один контакт). Программа должна:
- Добавлять новый контакт (имя и номер)
- Показывать все контакты
- Искать контакт по имени (выводить номер)
- Удалять контакт по имени
- Показывать количество контактов
Подсказка: при удалении контакта удаляй элемент из обоих списков на одной и той же позиции.
Удачи в программировании! Помни: лучший способ научиться – это практиковаться каждый день.