Программирование • 4 февраля 2026 • 5 мин чтения

Вопросы и задачи на собеседовании по Java в 2026 году

Рассказываем, какие темы стоит повторить перед собеседованием на позицию Java-разработчика.

Подготовка к интервью по Java

Можно попытаться выучить список вопросов, как билеты перед экзаменом. Но в реальности интервью устроены иначе: один и тот же вопрос могут задать десятью способами, а дальше поведут в детали. Зато хорошая новость в том, что набор тем почти не меняется — отличается только уровень глубины. Для junior чаще всего достаточно уровня «понимаю концепт и могу применить». От middle обычно ждут, что он умеет объяснить, «почему так», видит типовые ошибки и может их предотвратить. А senior почти всегда проверяют на понимание внутреннего устройства, последствий решений и компромиссов и часто добавляют этап систем-дизайна.

Проходить собеседования и быть готовым к самым сложным вопросам учат на курсе «Java-разработчик». За 10 месяцев студенты осваивают профессию и получают помощь в поиске работы. Выпускникам помогают оформить портфолио и правильно себя презентовать.

Общие вопросы по Java

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

Вопросы Ответы
Чем отличаются JVM, JRE и JDK? JVM (Java Virtual Machine) — это среда выполнения: она загружает классы, проверяет байткод, выполняет его (в том числе через JIT-компиляцию), управляет памятью и потоками и отвечает за runtime-механизмы вроде сборки мусора.

JRE (Java Runtime Environment) — это всё, что нужно, чтобы запустить Java-приложение: сама JVM + стандартные библиотеки и runtime-компоненты (то есть без инструментов разработки).

JDK (Java Development Kit) — это комплект для разработки: включает JRE и добавляет компилятор javac, отладчик и другие утилиты (например, для сборки, диагностики и анализа), то есть всё, что нужно, чтобы писать, собирать и исследовать приложение.

На какой версии Java вы работали? Что поменялось в Java 8/11/17/21? Во-первых, после Java 8 рынок в основном ориентируется на LTS-релизы (11/17/21), поэтому апгрейды стали регулярной частью поддержки: важно держать зависимости совместимыми и планировать обновления.

Во-вторых, начиная с Java 9 появилась модульная система (JPMS) и ужесточился доступ к внутренним API JDK — поэтому при миграциях иногда возникают проблемы с библиотеками и рефлексией и много времени уходит на обновление экосистемы и сборки.

В-третьих, язык и стандартная библиотека заметно эволюционировали в сторону более компактного и безопасного кода: records упрощают DTO и value-объекты, sealed classes позволяют контролировать иерархии, современный switch/pattern matching снижает объём шаблонного кода. В Java 21 отдельно выделяются virtual threads (Loom) — это меняет подход к конкурентному коду в задачах с большим количеством блокирующих операций.

Что такое bytecode? Bytecode — это промежуточный «машиночитаемый» формат .class, который получается после компиляции Java-кода. Он не привязан к конкретной ОС или процессору.
Был ли опыт миграции между версиями Java? Какие есть риски? Чаще всего риски не в синтаксисе, а в окружении: несовместимые зависимости, проблемы из-за модулей и доступа к внутренним API (Java 9+) и рантайм-нюансы (параметры JVM, контейнеры, возможные регрессии). Обычно миграция — это обновление библиотек, прогон тестов и внимательный мониторинг после выката.
Как готовиться к вопросам?
Вспомните, что менялось между Java 8/11/17/21 и как это влияет на работу: стиль кода, совместимость библиотек, поддержку и деплой. Повторите базовую структуру: байткод → JIT → рантайм. Подготовьте пример миграции Java-версии из практики: какие риски возникали (несовместимые зависимости, ограничения после Java 9+ из-за модулей/рефлексии, рантайм-нюансы), как вы их закрывали (обновление зависимостей, прогон тестов, проверка на окружении и мониторинг после выката).

Отдельно вспомните базовую модель памяти JVM: чем отличаются stack и heap, что хранится в Metaspace и почему объекты в Java создаются в heap, а в stack обычно лежат ссылки и данные вызова метода.

По GC важно знать, какие сборщики бывают: Serial, Parallel, G1 и ZGC. Ещё нужно на базовом уровне понимать, как вообще работает сборка мусора: программа создаёт объекты, часть из них со временем становится не нужна, GC находит такие объекты и освобождает память, чтобы её можно было снова использовать.

Базовые вопросы по синтаксису и ООП

ООП-вопросы кажутся базовыми, но подвох почти всегда в деталях. Важно не выучить определения, а понимать, как это влияет на код и его поддержку. Вот что спрашивают чаще всего.

Вопросы Ответы
Overload и override — в чём разница? Overload — это методы с одним именем, но с разными параметрами; выбор происходит на этапе компиляции.

Override — переопределение метода в наследнике; выбирается в рантайме через полиморфизм.

Checked- и unchecked-исключения — когда что использовать? Checked-исключения заставляют явно обрабатывать ошибку и влияют на API. Unchecked обычно используют для ошибок программирования или ситуаций, которые невозможно или не нужно корректно обрабатывать на уровне вызывающего кода. Выбор зависит от того, ожидаемая это ветка поведения или аварийная.
Что такое generics и зачем нужны wildcard’ы? Generics нужны, чтобы обеспечить типобезопасность на этапе компиляции и избавиться от лишних кастов и ClassCastException в рантайме.

При этом List<Dog> не является List<Animal>, потому что в Java обобщённые типы не поднимаются по наследованию: иначе можно было бы добавить Cat в список собак через ссылку типа List<Animal>.

Wildcard’ы позволяют писать более гибкие API, которые принимают семейство типов, а не один конкретный.

? extends T используют, когда коллекция выступает «источником» значений (в основном читаем), поэтому безопасно читать T, но добавлять нельзя.

? super T используют, когда коллекция «принимает» значения (в основном пишем): можно добавлять T, но при чтении гарантирован только Object (PECS).

Зачем нужен контракт equals/hashCode? Чтобы корректно определять логическое равенство объектов. У equals есть строгий контракт (рефлексивность, симметричность, транзитивность), а hashCode обязан быть с ним согласован. В этом месте много подводных камней: важно выбирать стабильные поля для сравнения и понимать, как устроить hashCode, чтобы он был и корректным, и качественным (например, не собирать его из полей, которые могут меняться, и не делать его слишком примитивным, чтобы не провоцировать коллизии).

Чаще всего после этого вопроса интервьюер логично переходит к теме коллекций — так как именно от equals/hashCode зависит поведение HashMap и HashSet и то, что происходит, если ключ внезапно «изменился». Про это — в следующем блоке.

Как готовиться здесь?
Освежите базовую теорию и термины по Java Core и ООП: перегрузка и переопределение, принципы ООП, интерфейсы и абстрактные классы, контракты equals/hashCode, исключения и generics. Отдельно повторите «языковую базу», о которой часто спрашивают вместе с ООП: модификаторы доступа, static и final, области видимости и порядок инициализации полей.

Восполните знания по строкам: == vs equals, String immutability, String pool, разницу между строковыми литералами и new String (), почему конкатенация в цикле — плохая идея (и когда включается StringBuilder).

Отдельно повторите Optional: зачем он вообще появился, как его правильно использовать в API и почему Optional обычно не делают полями сущностей/DTO. Полезно вспомнить самые частые операции и то, в каких местах они реально упрощают код, а где только мешают.

Коллекции и работа с данными

Коллекции — один из самых частых блоков на Java-интервью. Через них легко проверить сразу несколько вещей: умеете ли вы выбирать структуру данных под задачу, понимаете ли сложность операций и знаете ли типовые ошибки, которые потом дорого чинить в проде. Вот что спрашивают чаще всего.

Вопросы Ответы
ArrayList или LinkedList — что выбрать? В большинстве случаев — ArrayList. Он обычно быстрее и экономнее по памяти, потому что элементы лежат рядом и лучше работают с CPU cache. LinkedList имеет смысл в редких сценариях с частыми вставками/удалениями в середине, когда позиция уже найдена, но на практике его выбирают заметно реже, чем кажется.
HashMap и TreeMap — чем отличаются? HashMap даёт средний доступ O (1) без упорядочивания. TreeMap хранит ключи отсортированными, и операции идут за O (log n). Если нужен порядок, диапазонные запросы или «найти ближайший ключ» — TreeMap оправдан.
Как работает HashMap внутри? HashMap берёт hashCode () ключа, превращает его в индекс и по нему выбирает корзину (bucket). Если разные ключи попали в одну и ту же корзину, это коллизия: тогда внутри корзины элементы хранятся вместе и при поиске дополнительно сравниваются через equals (). В современных версиях Java при большом количестве коллизий корзина может «усложниться» (из списка превратиться в дерево), чтобы поиск не становился слишком медленным. Когда карта вырастает выше порога (capacity × load factor), она делает resize: увеличивает внутренний массив и перераспределяет элементы, поэтому это «дорогая» операция. Поэтому hashCode важен по двум причинам: он должен быть согласован с equals, и он должен хорошо распределять ключи, чтобы коллизий было мало и доступ оставался близким к O (1).

Про HashMap вообще можно задать очень много уточняющих вопросов, и интервьюеры этим часто пользуются. Например, как именно она хранится в памяти, что происходит при resize и почему это может внезапно ударить по производительности, чем плохой hashCode опасен не только логически, но и практически. Почти всегда всплывает тема ключей: какие объекты можно использовать в качестве ключа, почему они должны быть логически неизменяемыми и что ломается, если ключ меняется после добавления в карту. Отсюда же обычно уходят в разговор про immutability в целом — зачем делать объекты неизменяемыми, как это упрощает работу с коллекциями и многопоточностью.

Как готовиться здесь?
Вспомните, как устроены коллекции в Java: основные интерфейсы (Collection, List, Set, Map, Queue/Deque) и популярные реализации, чем они отличаются по поведению. Затем освежите «стоимость» операций: насколько быстро работают доступ к элементу, добавление, удаление и поиск. Отдельно повторите ArrayList и HashMap: в каких задачах их выбирают, какие у них сильные и слабые стороны, какие типовые ошибки с ними встречаются.

Потоки и многопоточность

Многопоточность — самый сложный раздел в Java Core. Мало просто знать инструменты: важно понимать, как реально работают потоки, какие гарантии задаёт модель памяти Java (Java Memory Model), зачем вообще нужны примитивы синхронизации. Часто на этом блоке дают и небольшие практические задачи: написать потокобезопасный счётчик, поправить гонку данных или объяснить, почему конкретный код иногда работает, а иногда нет.
Вопросы Ответы
Как создать поток в Java? Либо создать Thread и передать ему Runnable, либо использовать ExecutorService и отправлять задачи в пул. В современных проектах чаще используют пулы, потому что они управляют количеством потоков и очередью задач.
Что такое состояние гонки (race condition)? Это ситуация, когда несколько потоков одновременно читают и изменяют общие данные и результат зависит от порядка выполнения. В итоге состояние может стать неправильным даже при правильном на вид коде.
Что такое deadlock? Взаимная блокировка: два (или больше) потока постоянно ждут друг друга, потому что каждый держит ресурс, который нужен другому, и не может продолжить.
Как обеспечить синхронизацию? Нужно защитить общий ресурс так, чтобы в критической секции был только один поток и чтобы изменения были видны другим потокам. Для этого используют synchronized, локи, атомарные типы (Atomic*) и потокобезопасные структуры данных — выбор зависит от задачи.
Что такое локи (locks)? Это явные механизмы блокировки, которые работают похожим образом на synchronized, но дают больше контроля: можно попробовать взять блокировку с таймаутом, освобождать в нужном месте, использовать разные режимы (например, read/write).
Что такое ExecutorService? Это интерфейс для запуска задач в пуле потоков. Он управляет потоками и очередью: позволяет ограничивать параллелизм, отправлять задачи, получать результат (Future), задавать таймауты и корректно завершать выполнение.
Чем Runnable отличается от Callable? Runnable — это задача, которая ничего не возвращает и не бросает checked-исключения: у неё метод run () без результата. Callable — задача, которая возвращает результат (метод call () возвращает T) и может бросать checked-исключения. В ExecutorService Runnable подходит для «просто выполнить», а Callable — когда нужен результат, который потом можно получить через Future.
Как готовиться здесь?
Вспомните, что такое многопоточность и зачем она нужна: где это ускоряет работу, а где только усложняет код. Освежите ключевую идею: если потоки разделяют состояние, нужно заранее понимать, что именно является общими данными и как вы защищаете их от одновременных изменений, чтобы сохранять согласованность.

Дальше повторите основные инструменты Java: как создавать и запускать потоки (Thread, Runnable, Callable), как управлять выполнением задач через ExecutorService и пулы потоков, какие гарантии дают synchronized и volatile. Полезно руками написать несколько коротких примеров, чтобы уверенно объяснять, как выглядит синхронизация в коде и где обычно допускают ошибки. Отдельно освежите потокобезопасные структуры данных: какие коллекции считаются thread-safe, какие реализации есть в java.util.concurrent и когда их использование снимает необходимость в ручной синхронизации.

Stream API и функциональное программирование

Stream API и функциональный стиль давно используются в обычном Java-коде. Здесь важно понимать, как стримы выполняются, чем отличаются основные операции и где их применение может быть неудачным. Вот что спрашивают чаще всего.
Вопросы Ответы
map и flatMap — в чём разница? map используют, когда каждому элементу соответствует один результат, а flatMap — когда одному элементу соответствует несколько результатов и их нужно объединить в один общий список, а не получить «список списков».
Какие бывают операции в Stream API? Операции делятся на промежуточные и терминальные. Промежуточные (map, filter, sorted) возвращают новый stream и не выполняются сразу. Терминальные (collect, reduce, forEach, count) запускают выполнение и дают результат.
Почему parallelStream не всегда быстрее? Потому что распараллеливание означает накладные расходы: разбиение работы, синхронизацию и сбор результата. На небольших объёмах данных или при операциях с ожиданием это часто только замедляет выполнение.
Что такое функциональный интерфейс в Java? Это интерфейс с одним абстрактным методом, который можно реализовать помощью лямбды. В Java есть готовые функциональные интерфейсы в java.util.function, например Predicate (проверка условия), Function (преобразование), Supplier (поставщик значения), Consumer (обработка без результата), а также варианты для примитивов (IntPredicate, LongFunction и т. д.). Аннотация @FunctionalInterface не обязательна, но помогает зафиксировать контракт и ловить ошибки при изменениях.
Что такое method reference и чем он отличается от лямбды? Это более короткая запись той же идеи, когда сигнатура совпадает. По смыслу то же самое, разница — в читаемости.
Можно ли перегружать методы, принимающие разные функциональные интерфейсы? Да, но легко получить неоднозначность при вызове с лямбдой: компилятор может не понять, какую перегрузку выбрать. Тогда приходится явно указывать тип или использовать cast.
Как готовиться здесь?
Вспомните основные операции Stream API (map, flatMap, filter, sorted) и терминальные операции (collect, count). Потренируйтесь на простых вещах: отфильтровать данные, отсортировать, сделать groupingBy, собрать результат в List и Map (в том числе через toMap).

По функциональному стилю достаточно освежить лямбды и самые частые функциональные интерфейсы (Predicate, Function, Consumer, Supplier) и пару раз написать код с method reference. В этом блоке часто дают маленькие задания «написать стрим-цепочку», поэтому лучше заранее потренироваться руками, чтобы не вспоминать синтаксис на интервью.

Spring Framework и экосистема

Spring кажется простым, пока всё работает само собой. Но на интервью быстро уходят в то, где заканчивается привычный уровень и начинается механика: как создаются бины, откуда берутся прокси, где проходит граница транзакции и почему ожидаемое поведение иногда не срабатывает. Что спрашивают чаще всего.
Вопросы Ответы
Жизненный цикл бина — что происходит от создания до готовности? Spring создаёт объект бина, потом заполняет ему зависимости. После этого выполняется инициализация — например, метод с @PostConstruct или заданный init-метод. Когда приложение завершается и контекст закрывается, Spring вызывает методы завершения — например, @PreDestroy или destroy-метод. Запомните, что иногда Spring отдаёт не сам объект, а прокси вокруг него (например, для транзакций и AOP), поэтому то, «что реально вызывается», может отличаться от прямого вызова метода.
Чем отличаются @Component, @Service, @Repository? Все три аннотации регистрируют класс как Spring-компонент. Разница в назначении и в некоторых механизмах: @Service обычно ставят на бизнес-логику, @Repository — на слой доступа к данным, Spring может выполнять перевод исключений из JDBC/JPA в свои исключения. @Component — общий вариант без дополнительного смысла.
Зачем нужна @Transactional и как она работает? Она нужна, чтобы выполнять операции с БД в транзакции: либо всё фиксируется, либо откатывается. В Spring транзакции чаще всего подключаются через прокси: при вызове метода через Spring-бин открывается транзакция, а после выполнения происходит commit или rollback — в зависимости от результата и типа исключения.
Что такое dependency injection и какие виды инъекции бывают? Что лучше? DI — это когда зависимости передаются объекту извне, а не создаются внутри. Основные варианты: инъекция через конструктор, сеттер и поле. Чаще всего предпочитают конструктор: зависимости явные, объект проще сделать корректно инициализированным, его удобнее тестировать.
Что такое AOP и зачем нужны advice? AOP позволяет добавлять общий код «вокруг» вызова методов без дублирования в каждом классе: логирование, метрики, безопасность, транзакции. advice — это правило, что выполнить относительно вызова метода: до (before), после (after), при исключении (afterThrowing) или обернуть вызов целиком (around) и контролировать выполнение.
Как сделать глобальный обработчик ошибок в Spring? Обычно используют @ControllerAdvice / @RestControllerAdvice и методы с @ExceptionHandler, которые ловят нужные исключения и возвращают единый формат ответа (статус, сообщение, детали). Это помогает сохранять обработку ошибок централизованной и одинаковой для всех контроллеров.
Как готовиться здесь?
В Spring почти всегда можно уйти в детали, поэтому цель — держать в голове механику: как контейнер создаёт бины, какие есть скоупы, где появляются прокси, и как из-за этого меняется поведение транзакций и AOP. Если в вакансии есть Spring Data, освежите разницу между Repository / CrudRepository / PagingAndSortingRepository / JpaRepository, как работает @Query, пагинация/сортировка (Pageable) и типовые ORM-проблемы вроде N+1 и способов их избегать (join fetch, @EntityGraph). 

Если есть Spring Security, повторите цепочку фильтров, SecurityContext, разницу authentication/authorization, роли vs authorities, JWT vs session и ограничения доступа на URL/методах (@PreAuthorize). Полезно помнить, как формируются 401/403 и как настроить единый формат ошибок безопасности.

Базы данных и JPA/Hibernate

Здесь будут спрашивать про то, как приложение читает и пишет данные и почему производительность часто упирается не в Java-код, а в запросы. Здесь важно понимать индексы, JOIN’ы, транзакции и то, как ORM формирует SQL. Что спрашивают чаще всего:
Вопросы Ответы
Зачем нужны индексы? Какие у них плюсы и минусы? Индексы нужны, чтобы база могла быстрее находить строки по условиям в WHERE, JOIN, ORDER BY. Плюс: запросы на чтение становятся заметно быстрее. Минусы: индексы занимают место и замедляют запись — при INSERT/UPDATE/DELETE их тоже нужно обновлять. Поэтому индексы — это всегда компромисс между скоростью чтения и стоимостью записи.
Какие типы индексов бывают? Самые распространённые — B-tree (универсальный вариант для большинства запросов), Hash (быстрые по точному равенству, но редко используются в проде), составные индексы (по нескольким колонкам) и частичные индексы (по условию). В некоторых СУБД есть специализированные варианты — например, GIN/GiST для JSON и полнотекстового поиска. На интервью обычно ожидают, что ты понимаешь, чем составной индекс отличается от обычного и почему порядок колонок в нём важен.
Что такое N+1 и как от него избавиться? Это ситуация, когда сначала загружается список сущностей одним запросом, а потом для каждой сущности отдельно подгружаются связанные данные — и запросов становится N+1. В JPA это решают через fetch join, @EntityGraph, batch fetching или пересмотр запроса так, чтобы нужные данные доставались сразу. Иногда проще изменить DTO и не тянуть лишние связи.
Как оптимизировать сложный SQL-запрос? Обычно начинают с плана запроса (EXPLAIN): смотрят, какие индексы используются, где идут full scan и «дорогие» JOIN’ы. Дальше упрощают сам запрос: убирают лишние JOIN’ы и поля, добавляют или меняют индексы, переписывают подзапросы в JOIN’ы (или наоборот), проверяют селективность условий и актуальность статистики.
Как готовиться здесь?
Повторите базовый SQL: SELECT, WHERE, JOIN, GROUP BY, HAVING, сортировку и лимиты — на интервью часто просят написать запрос руками или разобрать готовый. Отдельно освежите индексы: зачем они нужны, какие дают плюсы/минусы, какие бывают (включая составные). 

По JPA/Hibernate важно понимать, что такое ORM и зачем он нужен: он связывает объекты и таблицы и снимает много рутины, но при этом всегда нужно следить за тем, какой SQL реально выполняется.

Практические задачи на собеседовании

Первый вид — алгоритмы: задачи на логику и эффективность решения (массивы, строки, поиск, динамика, графы — что угодно). Тут важно быстро выбрать подход, проговорить сложность и написать рабочее решение. Подготовиться можно путём регулярной практики на LeetCode/HackerRank и повторения алгоритмики. 

Второй вид — задачи «как на проекте»: реализовать API или кусок бизнес-логики, продумать валидацию, ошибки, тесты и границы ответственности. Универсального способа «натренировать» такие задачи нет, потому что форматов слишком много. Такой формат ближе к тому, что приходится ежедневно делать на работе: разобрать требования, предложить решение, учесть детали и довести до рабочего состояния.

Советы по подготовке к интервью и его прохождению

Анастасия Фомкина
  • Ведите заметки после каждого интервью: что спрашивали, где было сложно и что стоит повторить. Со временем это превращается в ваш личный список тем, и следующая подготовка идёт быстрее и спокойнее.
  • Неудачное интервью редко говорит что-то про вас как про разработчика. На результат сильно влияют волнение, формат, вопросы и даже то, насколько вы выспались. Поэтому перед интервью лучше заранее разгрузить вечер и нормально поспать.
  • Прохождение интервью — это отдельный навык, который держится только благодаря практике. Если долго не ходить на собеседования, начинаешь отвечать хуже просто потому, что отвыкаешь от формата и темпа. Хорошо помогают мок-интервью, чтобы не бояться процесса и чувствовать себя увереннее.
  • На практических задачах полезно проговаривать мысли вслух: как вы поняли задачу, какие допущения сделали, какие варианты решения видите и почему выбираете один. И не бойтесь задавать уточняющие вопросы — это нормальная часть работы, и на интервью это обычно только плюс. 
Статью подготовили:
Анастасия Фомкина
Яндекс Практикум
Автор курса «Мидл Java‑разработчик», Software Engineer в компании Masabi
Валентина Бокова
Яндекс Практикум
Редактор
Анастасия Павлова
Яндекс Практикум
Иллюстратор

Подпишитесь на наш ежемесячный дайджест статей —
а мы подарим вам полезную книгу про обучение!

Поделиться
Теперь вы можете получать материалы, подобранные под ваши скилы и интересы, в Telegram. Просто подпишитесь на бота Практикума.