Підготовка до співбесіди · IT та розробка

Питання на співбесіді Java-розробника

Питання на співбесіді Java-розробника: Java Core, колекції, багатопотоковість і віртуальні потоки Java 21+, Spring Boot, бази даних і архітектура. Для рівнів Junior, Middle і Senior — з прикладами відповідей.

Популярні теми

Junior Java Core

Навіщо перевизначати equals() і hashCode() разом?

Приклад відповіді

Контракт вимагає: якщо два об'єкти рівні за equals(), у них має бути однаковий hashCode(). Колекції на основі хешів (HashMap, HashSet) спочатку шукають кошик за хешем, а потім порівнюють через equals().

Якщо перевизначити лише equals(), два «рівні» об'єкти потраплять у різні кошики, і HashSet міститиме дублікати. Для простих носіїв даних у сучасній Java зручно використовувати record — він генерує обидва методи автоматично.

Junior Java Core

Чим відрізняються checked і unchecked винятки?

Приклад відповіді

Checked винятки (IOException, SQLException) компілятор змушує або обробити, або оголосити в throws. Unchecked — нащадки RuntimeException (NullPointerException, IllegalArgumentException) — обробляти не обов'язково.

Checked зазвичай описують очікувані зовнішні збої, unchecked — помилки програміста або порушення контракту. У Spring-проєктах частіше використовують unchecked винятки, а обробляють їх централізовано через @ControllerAdvice.

Junior Колекції

Чим ArrayList відрізняється від LinkedList?

Приклад відповіді

ArrayList зберігає елементи в масиві: доступ за індексом швидкий — O(1), а вставка в середину потребує зсуву елементів. LinkedList — двозв'язний список: вставка й видалення за наявного вузла швидкі, але пошук за індексом — O(n).

На практиці ArrayList майже завжди швидший через кращу роботу з кешем процесора, тому LinkedList використовують рідко — хіба що як черга, але для цього краще ArrayDeque.

Junior Java Core

Чому String у Java незмінний?

Приклад відповіді

Незмінність робить рядки безпечними для використання в кількох потоках, дає змогу кешувати хеш і зберігати однакові літерали в String Pool. Також це важливо для безпеки: рядок із шляхом до файлу чи URL не можна змінити після перевірки.

Для багаторазового складання рядка в циклі використовують StringBuilder, щоб не створювати багато проміжних об'єктів.

Middle Колекції

Як влаштований HashMap усередині?

Приклад відповіді

HashMap — масив кошиків. Для ключа обчислюється хеш, за ним визначається індекс кошика. Якщо кілька ключів потрапляють в один кошик, вони зберігаються у списку, а з Java 8 при великій кількості колізій (понад 8) список перетворюється на червоно-чорне дерево.

Коли заповненість перевищує load factor (0.75), масив подвоюється і елементи перерозподіляються. HashMap не потокобезпечний — для кількох потоків використовують ConcurrentHashMap.

Middle Багатопотоковість

Що таке віртуальні потоки (Java 21) і коли вони корисні?

Приклад відповіді

Віртуальні потоки — легкі потоки, якими керує JVM, а не ОС. Їх можна створювати мільйонами: коли потік чекає на I/O (запит до БД, HTTP), він звільняє платформний потік-носій.

Вони найкорисніші для серверів із великою кількістю блокуючих операцій — можна писати простий синхронний код замість реактивного. Для CPU-задач вигоди немає. Варто пам'ятати про pinning: довгі блоки synchronized з I/O могли прив'язувати потік до носія (у Java 24 це виправили), а також не варто кешувати дорогі об'єкти в ThreadLocal.

Middle Spring

Як працює @Transactional і чому вона іноді «не спрацьовує»?

Приклад відповіді

Spring створює проксі навколо біна: проксі відкриває транзакцію перед викликом методу і фіксує або відкочує її після. Тому типові пастки:

  • виклик транзакційного методу з того самого класу (this.method()) обходить проксі;
  • анотація на private методі не працює;
  • за замовчуванням відкат лише для unchecked винятків — для checked потрібно rollbackFor.

Також варто розуміти propagation (REQUIRED, REQUIRES_NEW) і не тримати транзакцію відкритою під час довгих зовнішніх викликів.

Middle Spring

Що таке проблема N+1 у JPA/Hibernate і як її вирішити?

Приклад відповіді

Коли завантажуємо список сутностей, а потім звертаємося до лінивої (LAZY) асоціації кожної, Hibernate виконує окремий запит на кожен елемент.

Рішення: JOIN FETCH у JPQL, @EntityGraph, batch fetching (hibernate.default_batch_fetch_size) або DTO-проєкції, коли потрібні лише кілька полів. Виявити проблему допомагає логування SQL або інструменти на кшталт Hypersistence Optimizer.

Senior Архітектура й JVM

Як ви розслідуєте витік пам'яті або часті паузи GC у продакшні?

Приклад відповіді

Спочатку метрики: графіки heap після GC, частота й тривалість пауз (Micrometer, Prometheus, JFR). Якщо пам'ять після кожного повного GC зростає — ймовірний витік.

Далі — heap dump (jcmd <pid> GC.heap_dump) і аналіз в Eclipse MAT: які об'єкти утримуються і хто тримає посилання (кеші без обмежень, статичні колекції, ThreadLocal). Для пауз — вибір GC під задачу (G1 за замовчуванням, ZGC для низьких затримок) і налаштування розміру heap під ліміти контейнера.

Senior Архітектура й JVM

Як забезпечити узгодженість даних між мікросервісами без розподілених транзакцій?

Приклад відповіді

Двофазний коміт між сервісами майже не використовують — він крихкий і повільний. Натомість:

  • Saga — послідовність локальних транзакцій із компенсуючими діями при збої (оркестрація або хореографія через події);
  • Transactional Outbox — подія записується в тій самій транзакції, що й дані, і надійно публікується в Kafka;
  • ідемпотентні споживачі, щоб повторна доставка не ламала дані.

Важливо чесно сказати бізнесу, що дані будуть узгоджені з затримкою (eventual consistency), і спроєктувати інтерфейс під це.

Senior Багатопотоковість

Що таке Java Memory Model і навіщо volatile?

Приклад відповіді

JMM визначає, коли запис одного потоку стає видимим іншим. Без синхронізації компілятор і процесор можуть переставляти інструкції, а потік — бачити застаріле значення з кешу.

volatile гарантує видимість і забороняє певні перестановки (відношення happens-before), але не робить складені операції атомарними: count++ на volatile-змінній однаково небезпечний. Для лічильників — AtomicLong / LongAdder, для складних інваріантів — блокування.

Senior Архітектура й JVM

Як ви оцінюєте доцільність переходу на нову LTS-версію Java (наприклад, з 17 на 21 або 25)?

Приклад відповіді

Аргументи «за»: віртуальні потоки, pattern matching і record patterns, sequenced collections, покращення GC і швидкодії, довша підтримка безпеки.

План: перевірити сумісність залежностей і фреймворків (Spring Boot 3.x), запустити тести й статичний аналіз, порівняти навантажувальні тести та споживання пам'яті, оновлювати поступово — спершу некритичні сервіси. Добре навести приклад реальної міграції та її результати в цифрах.

Типові помилки кандидатів

  • Знати лише Java 8 і не орієнтуватися в record, sealed-класах і віртуальних потоках.
  • Пояснювати `@Transactional` як «магію», не розуміючи роботи проксі.
  • Використовувати `FetchType.EAGER` скрізь як рішення проблем продуктивності.
  • Не вміти пояснити, як ваш код поводиться при одночасному доступі кількох потоків.
  • Відповідати теорією без прикладів реальних інцидентів і того, як їх вирішували.

Як підготуватися

  • Повторіть внутрішню будову HashMap і контракт equals/hashCode — їх питають майже завжди.
  • Розберіться у віртуальних потоках і нових можливостях Java 21+.
  • Підготуйте історію про оптимізацію: що вимірювали, що змінили, який результат.
  • Попрактикуйтеся в задачах на Stream API та SQL без IDE.
  • Будьте готові намалювати архітектуру свого останнього проєкту.

Актуальні вакансії: Java Developer

Схожі професії

Перевірте знання перед співбесідою

Випадкові питання, таймер на кожну відповідь і розбір помилок наприкінці. Можна пройти кілька разів — питання щоразу інші.