Часть 1. Java Core (вопросы 1–20)
1. Что такое JVM, JRE, JDK? В чём разница?
- JVM (Java Virtual Machine) — виртуальная машина, исполняющая байт-код.
- JRE (Java Runtime Environment) = JVM + библиотеки (rt.jar и др.) — нужно для запуска.
- JDK (Java Development Kit) = JRE + компилятор (javac), отладчик, документация — нужно для разработки.
💡 С Java 11: javac и java поставляются вместе. Нет отдельного JRE — используйте jlink для сборки runtime.
2. Как работает сборщик мусора в Java? Какие алгоритмы вы знаете?
- GC удаляет объекты, на которые нет ссылок.
- Алгоритмы:Serial GC — однопоточный, для маленьких приложений.
Parallel GC — многопоточный, фокус на throughput (по умолчанию до Java 8).
G1 GC — для heap > 4 ГБ, минимизирует паузы (по умолчанию с Java 9).
ZGC / Shenandoah — low-latency GC (доступны в Java 11+, но не по умолчанию).
✅ В Java 11 G1 — стандарт. Используйте -XX:+UseG1GC.
3. Что такое final, finally, finalize?
- final — модификатор: переменная (неизменяемая), метод (нельзя переопределить), класс (нельзя наследовать).
- finally — блок в try-catch, который выполняется всегда (кроме System.exit()).
- finalize() — устаревший метод, вызывался перед GC. Не используйте! Вместо него — Cleaner или явное управление ресурсами.
4. В чём разница между == и .equals()?
- == сравнивает ссылки (адреса в памяти).
- .equals() — логическое сравнение (по умолчанию делегирует ==, но можно переопределить).
String a = new String("test");
String b = new String("test");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
⚠️ Переопределяя equals(), всегда переопределяйте hashCode()!
5. Что такое String, StringBuilder, StringBuffer?
- String — неизменяемый, потокобезопасный.
- StringBuilder — изменяемый, не потокобезопасный, быстрее.
- StringBuffer — изменяемый, потокобезопасный (методы synchronized), медленнее.
✅ Используйте StringBuilder в 99% случаев.
6. Что такое autoboxing и unboxing? Проблемы?
- Autoboxing: int → Integer.
- Unboxing: Integer → int.
Проблема:
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false! (кэш только до 127)
💡 Избегайте == для объектных типов.
7. Что такое var в Java 10+? Можно ли его использовать в полях?
- var — локальный вывод типа (local variable type inference).
- Работает только в локальных переменных, не в полях, не в параметрах методов.
var list = new ArrayList<String>(); // OK
// private var name; // ОШИБКА!
✅ Удобно, но не злоупотребляйте — читаемость важнее.
8. Что такое Optional? Зачем он нужен?
- Обёртка для предотвращения NullPointerException.
- Методы: of(), ofNullable(), orElse(), ifPresent(), map(), flatMap().
Optional<String> opt = Optional.ofNullable(getName());
String name = opt.orElse("default");
❌ Не используйте Optional как поле или в коллекциях.
9. Что такое запись (Record) в Java?
- Появилось в Java 14 (preview), стабильно в 16+. В Java 11 — недоступно.
- Компактный способ создания immutable DTO:
// Java 16+
record Person(String name, int age) {}
💡 В Java 11 — используйте Lombok (@Data, @Value) или обычные классы.
10. Как обрабатывать исключения? Checked vs unchecked?
- Checked (IOException) — должны быть обработаны или объявлены в throws.
- Unchecked (RuntimeException, Error) — не обязаны.
✅ Лучше оборачивать checked-исключения в unchecked (например, DataAccessException в Spring).
(Продолжение: вопросы 11–20 — про интерфейсы, абстрактные классы, внутренние классы, рефлексия, аннотации, модули, лямбды, Stream API, функциональные интерфейсы, работа с датами в Java 8+)
💡 Stream API — must-know:
List<String> names = users.stream()
.filter(u -> u.getAge() > 18)
.map(User::getName)
.collect(Collectors.toList());
Часть 2. Коллекции (вопросы 21–30)
21. Как устроены ArrayList и LinkedList? Когда что использовать?
- ArrayList — массив, быстрый доступ по индексу (O(1)), медленные вставки в начало (O(n)).
- LinkedList — двусвязный список, быстрые вставки/удаления (O(1)), медленный доступ по индексу (O(n)).
✅ Почти всегда используйте ArrayList. LinkedList — редкий кейс.
22. Как работает HashMap? Что такое коллизия?
- Хранит пары key → value в buckets.
- Хеш-функция определяет bucket.
- При коллизии (одинаковый hash) — цепочка (до Java 8) или дерево (если >8 элементов в bucket, с Java 8).
⚠️ Ключ должен корректно реализовывать hashCode() и equals().
23. Почему важно переопределять hashCode() при equals()?
Если два объекта равны по equals(), их hashCode() должен быть одинаковым. Иначе HashMap не найдёт значение.
24. Чем ConcurrentHashMap отличается от Collections.synchronizedMap()?
- synchronizedMap — блокирует весь мап на каждую операцию.
- ConcurrentHashMap — блокирует только bucket, позволяет параллельное чтение.
✅ Используйте ConcurrentHashMap для высоконагруженных систем.
25. Что такое fail-fast и fail-safe итераторы?
- Fail-fast (ArrayList, HashMap) — бросает ConcurrentModificationException, если коллекция изменена во время итерации.
- Fail-safe (ConcurrentHashMap, CopyOnWriteArrayList) — работает с копией, не бросает исключение.
(Вопросы 26–30: TreeMap, LinkedHashMap, WeakHashMap, BlockingQueue, Deque)
🔹 Часть 3. Многопоточность (вопросы 31–50)
31. Что такое volatile?
- Гарантирует, что запись в переменную будет видна всем потокам сразу.
- Запрещает reordering компилятором/JIT.
✅ Используется для флагов остановки:
private volatile boolean running = true;
32. Что такое synchronized?
- Блокирует монитор объекта/класса.
- Гарантирует атомарность и видимость.
public synchronized void increment() { counter++; }
⚠️ Может вызывать deadlock. Предпочитайте java.util.concurrent.
33. Что такое ExecutorService? Зачем он нужен?
- Пул потоков для выполнения задач.
- Типы: newFixedThreadPool, newCachedThreadPool, newSingleThreadExecutor.
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("Task"));
✅ Всегда вызывайте shutdown()!
34. Что такое CompletableFuture?
- Асинхронный результат с возможностью chaining’а.
CompletableFuture.supplyAsync(() -> fetchData())
.thenApply(data -> process(data))
.thenAccept(result -> save(result));
✅ Используйте вместо Future.
35. Что такое CountDownLatch, CyclicBarrier, Semaphore?
- CountDownLatch — ждать N событий (одноразовый).
- CyclicBarrier — ждать, пока N потоков достигнут барьера (многоразовый).
- Semaphore — ограничить количество одновременных доступов (например, к БД).
💡 Примеры см. в статье «2 практических примера CountDownLatch».
(Вопросы 36–50: deadlock, livelock, race condition, atomic variables, ForkJoinPool, ThreadLocal, memory model, happens-before, AQS, ReentrantLock)
🔹 Часть 4. Hibernate / JPA (вопросы 51–70)
51. Что такое кэш первого уровня?
- Это Identity Map в рамках одной Session.
- Гарантирует, что для одного ID — один объект.
✅ Подробнее см. статью «Кэш первого уровня и Identity Map».
52. Когда Hibernate отправляет SQL в БД?
- При flush() (автоматически перед коммитом транзакции или запросом).
- Не при простом изменении managed-объекта.
✅ Подробнее см. статью «Когда изменения Entity попадают в БД».
53. Что такое LazyInitializationException? Как избежать?
- Возникает, когда вы пытаетесь загрузить lazy-коллекцию после закрытия Session.
Решения:
- JOIN FETCH в JPQL,
- Open Session in View (не рекомендуется),
- DTO projection.
54. Что такое N+1 проблема? Как решить?
- Запрос 1 раз — получить N сущностей, затем N запросов — для каждой связи.
Решение: JOIN FETCH или @EntityGraph.
55. Отличие persist() vs save() vs merge()?
- persist() — для transient объектов, не гарантирует ID до flush.
- save() — Hibernate-specific, возвращает ID сразу.
- merge() — для detached объектов, возвращает managed копию.
✅ В JPA — используйте persist() и merge().
(Вопросы 56–70: каскадирование, стратегии генерации ID, optimistic/pessimistic locking, second-level cache, dirty checking, proxy, FetchType, CascadeType, @Embedded, @ElementCollection)
🔹 Часть 5. Spring Framework (вопросы 71–90)
71. Что такое IoC и DI?
- Inversion of Control — управление зависимостями передаётся контейнеру.
- Dependency Injection — способ внедрения зависимостей (через конструктор, setter, field).
✅ Конструкторная DI — предпочтительна.
72. Как работает @Autowired?
- Автоматически внедряет бины по типу.
- Если несколько бинов — используйте @Qualifier.
⚠️ Избегайте field injection — используйте constructor injection.
73. Что такое @Primary, @Qualifier?
- @Primary — помечает основной бин, если есть несколько кандидатов.
- @Qualifier("name") — явно указывает, какой бин использовать.
74. Как работает @Transactional?
- Создаёт прокси, который управляет транзакцией через AOP.
- По умолчанию: REQUIRED, rollback только при unchecked-исключениях.
⚠️ Не вызывайте @Transactional методы внутри того же класса — прокси не сработает!
75. Что такое Spring Profiles?
- Позволяют иметь разные конфигурации для dev, test, prod.
@Profile("prod")
@Configuration
public class ProdConfig { ... }
76. Что такое Spring Boot AutoConfiguration?
- Автоматически настраивает бины на основе classpath (например, если есть HikariCP — создаёт DataSource).
✅ Отключить: @EnableAutoConfiguration(exclude = ...).
77. Что такое Actuator?
- Эндпоинты для мониторинга: /health, /metrics, /env.
✅ Обязательно включайте в production.
78. Что такое Spring AOP? Когда использовать?
- Аспектно-ориентированное программирование: логгирование, транзакции, security.
⚠️ Работает только через прокси — не для private методов.
(Вопросы 79–90: Spring MVC, REST, ResponseEntity, ExceptionHandler, Validation, WebFlux, WebClient, Security, OAuth2, Cache, Retry, Scheduler, Test (MockMvc, @DataJpaTest))
🔹 Часть 6. Архитектура и DevOps (вопросы 91–100)
91. Что такое микросервисы? Плюсы и минусы?
- Плюсы: независимость, масштабируемость, технологическая свобода.
- Минусы: сложность, сетевые задержки, распределённые транзакции.
92. Как обеспечить отказоустойчивость?
- Circuit Breaker (Resilience4j),
- Retry,
- Timeout,
- Bulkhead.
93. Как организовать централизованное логгирование?
- ELK Stack (Elasticsearch, Logstash, Kibana) или Grafana Loki.
94. Что такое CI/CD?
- Continuous Integration / Continuous Delivery — автоматизация сборки, тестов, деплоя.
95. Как мониторить микросервисы?
- Prometheus + Grafana (метрики),
- Zipkin / Jaeger (трассировка),
- Health-checks.
96. Что такое Docker? Зачем он нужен?
- Контейнеризация: изолированная, воспроизводимая среда выполнения.
97. Как настроить безопасность в Spring Boot?
- Spring Security + OAuth2 / JWT,
- HTTPS,
- CORS,
- Rate limiting.
98. Как работать с конфигурацией в облаке?
- Spring Cloud Config Server,
- Kubernetes ConfigMap / Secrets.
99. Как тестировать микросервисы?
- Unit-тесты (JUnit, Mockito),
- Интеграционные (@SpringBootTest),
- Contract-тесты (Pact),
- Chaos Engineering (Chaos Monkey).
100. Как вы подходите к рефакторингу legacy-кода?
- Покрываете тестами,
- Выделяете границы,
- Применяете Strangler Fig Pattern,
- Постепенно заменяете.