Java Курс

Java Collections: ArrayList, HashMap и другие

Самоучитель Python 3, собранный из материалов данного сайта.Предназначен в основном для тех, кто хочет изучить язык программирования Python с нуля.

Урок 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. Создается новый массив большего размера (обычно в 1.5 раза больше).
  2. Все старые элементы копируются в новый массив.
  3. Старый массив удаляется сборщиком мусора.

Это занимает время, поэтому если заранее знаешь, что будет много элементов, можно задать начальную емкость:

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] – один контакт). Программа должна:

  • Добавлять новый контакт (имя и номер)
  • Показывать все контакты
  • Искать контакт по имени (выводить номер)
  • Удалять контакт по имени
  • Показывать количество контактов

Подсказка: при удалении контакта удаляй элемент из обоих списков на одной и той же позиции.

Удачи в программировании! Помни: лучший способ научиться – это практиковаться каждый день.