
Собеседование по Java: вопросы и три задачи с разбором
На собеседовании по Java полезно уметь объяснить, что произойдёт с данными, и проверить решение на границе условий. В этом практикуме разберём три задачи по коллекциям: поиск по ключу, удаление элементов и сортировку. Материал подготовила редакция Mentoring.digital.
Содержание статьи
Как пройти практикум с пользой
Сначала прочитайте только условие, запишите ожидаемый результат и предложите решение. После этого сравните код с разбором. Если ответ совпал, измените входные данные: пустая коллекция, повторяющиеся значения, минимальное и максимальное целое число часто раскрывают незамеченное условие.
Примеры рассчитаны на Java 17 и новее. В них используются записи record и метод Stream.toList(). Это учебные задания, а не подборка подтверждённых вопросов конкретного работодателя. Для запуска нужны импорты java.util.ArrayList, Comparator, HashMap, List, Map и Objects из пакета java.util. Методы и записи можно разместить внутри одного класса.
Задача 1. Почему HashMap не находит похожий ключ
Условие: в карте хранятся владельцы по идентификатору. В неё добавили пользователя с ID 7, а при чтении создали другой объект с тем же ID. Получите имя «Ирина», не перебирая все записи карты.
record UserKey(long id) {}
static String findOwner() {
Map<UserKey, String> owners = new HashMap<>();
owners.put(new UserKey(7), "Ирина");
return owners.get(new UserKey(7));
}Здесь два объекта new UserKey(7) равны по значению компонента записи. Сгенерированные для этой записи equals() и hashCode() согласованы, поэтому поиск по новому равному ключу возвращает сохранённое имя. Если вместо записи взять обычный класс без переопределения этих методов, унаследованный Object.equals() сравнивает ссылки: два отдельных экземпляра не становятся равными из-за одинакового поля.
Договор равенства требует, чтобы равные объекты имели одинаковый хеш-код. Обратное неверно: одинаковый хеш ещё не доказывает равенство. При собственной реализации класса согласованно определяйте оба метода. Изменение поля, участвующего в равенстве и вычислении хеша уже используемого ключа, может нарушить ожидаемый поиск в карте.
- Проверьте поиск по ID 7 и по отсутствующему ID 8. Во втором случае в этой карте результатом будет
null. - Сравните два ключа с одинаковыми и разными ID. Для равных ключей отдельно сравните хеши.
- Объясните, почему одна лишь замена
HashMapна другую реализацию карты не исправляет неверно заданное равенство.
Задача 2. Удалить выполненные задачи и сохранить исходный список
Дан список задач A, B, C, D. У A и C признак done равен true. Требуется вернуть новый изменяемый список B, D с прежним порядком элементов. Исходный список менять нельзя. Контракт этого примера допускает только непустые ссылки на задачи, а сам список не должен быть null.
record Task(String name, boolean done) {}
static List<Task> openTasks(List<Task> source) {
Objects.requireNonNull(source);
List<Task> result = new ArrayList<>(source);
result.removeIf(Task::done);
return result;
}Копирование создаёт отдельный контейнер, после чего removeIf удаляет из него элементы, для которых предикат истинен. Исходный контейнер остаётся прежним. Это поверхностная копия: в общем случае объекты внутри двух списков общие. В примере запись Task содержит строку и логический признак, а её компоненты после создания не переназначаются.
Удалять элементы напрямую из того же ArrayList внутри расширенного цикла for нельзя считать корректным решением. Итератор может обнаружить структурное изменение и выбросить ConcurrentModificationException, но исключение не гарантировано для любого такого обхода. Проверка должна оценивать результат и сохранность исходных данных, а не только отсутствие ошибки.
- Сравните исходный список с его снимком до вызова.
- Проверьте пустой список, список без выполненных задач и список, где выполнены все задачи.
- Добавьте элемент в результат и убедитесь, что исходный контейнер не изменился. Если нужна неизменяемая выдача, это отдельное условие контракта.
Задача 3. Отсортировать приоритеты без ошибки на больших числах
У заявок есть строковый ID и целочисленный приоритет. Нужен новый список по убыванию приоритета. При равенстве приоритетов упорядочьте заявки по ID по естественному порядку строк. Входной список, его элементы и ID не равны null.
record Ticket(String id, int priority) {}
static List<Ticket> orderedTickets(List<Ticket> source) {
Comparator<Ticket> order = Comparator
.comparingInt(Ticket::priority).reversed()
.thenComparing(Ticket::id);
return source.stream().sorted(order).toList();
}Сравнение через вычитание b.priority() - a.priority() опасно: результат может переполнить диапазон int и дать неверный знак. comparingInt задаёт сравнение целых чисел, reversed() меняет порядок по приоритету, а thenComparing определяет порядок при совпадении этого поля.
Для входа low: MIN_VALUE, B: 0, high: MAX_VALUE, A: 0 ожидаемый порядок ID: high, A, B, low. Исходный список не переставляется. Результат Stream.toList() неизменяемый: попытка добавить в него элемент вызывает UnsupportedOperationException. Если по условию нужен изменяемый контейнер, явно создайте из результата ArrayList.
Какие вопросы стоит уметь объяснить после решения
| Вопрос | Что должно быть в ответе |
|---|---|
| Чем равенство по ссылке отличается от равенства по значению? | Какие объекты считаются одинаковыми в модели и как это выражено в equals/hashCode. |
| Что именно копируется в new ArrayList<>(source)? | Новый контейнер с теми же ссылками на элементы; это не глубокое копирование. |
| Чем отличаются фильтрация и изменение исходного списка? | Побочные эффекты должны соответствовать явному условию задачи. |
| Зачем нужен второй критерий сортировки? | Он определяет результат для равных приоритетов. |
| Достаточно ли успешного запуска на одном наборе? | Нет. Нужны граничные случаи, проверки контракта и объяснение ограничений. |
Редакция скомпилировала эти примеры с целевым уровнем Java 17 и выполнила 15 проверок, включая равенство ключей, сохранность входного списка, крайние приоритеты и неизменяемость результата сортировки. Эти проверки относятся к опубликованным учебным условиям; они не подтверждают готовность ко всему техническому интервью.
Для самостоятельного продолжения измените одно условие: разрешите одинаковые ID или задайте правила для отсутствующего приоритета. Сначала определите ожидаемое поведение, затем меняйте код и проверки. Разобрать собственные решения можно с наставником по Java, а выстроить последовательную практику помогут курсы Java.
Оценки и отзывы о статье
Отзывы читателей0
Здесь пока нет отзывов. Расскажите, чем вам помогла статья.

