Вопросы уровня middle — многопоточность, JVM, коллекции изнутри, Stream API.
- Чем checked-исключения отличаются от unchecked? Middle
Checked (наследники Exception, кроме RuntimeException) компилятор требует объявить в throws или обработать. Unchecked (RuntimeException и Error) — нет. Выбор: checked — когда…
- Какое правило связывает equals() и hashCode()? Middle
Равные по equals объекты обязаны иметь равный hashCode; обратное не требуется — коллизии нормальны. Иначе HashMap и HashSet ищут в другой корзине и не находят равный объект: до…
- Что гарантирует ключевое слово volatile для переменной? Middle
volatile даёт видимость (запись сразу видна другим потокам) и запрет переупорядочивания вокруг обращения, но не атомарность: count++ на volatile-поле всё равно теряет обновления.
- Почему String в Java неизменяемый? Middle
Неизменяемость String даёт пул строк (литералы разделяются безопасно), кэш hashCode (строка — идеальный ключ HashMap), потокобезопасность без синхронизации и безопасность…
- Чем интерфейс отличается от абстрактного класса и что изменили default-методы? Middle
Интерфейс — контракт: класс может реализовать много интерфейсов, состояния (полей экземпляра) нет. Абстрактный класс — общая база с состоянием, конструктором и частичной…
- Чем промежуточные операции Stream отличаются от терминальных? Middle
Промежуточные операции (filter, map, sorted) ленивы и возвращают новый Stream — они только описывают конвейер. Терминальная (collect, forEach, count, findFirst) запускает…
- Чем HashMap отличается от Hashtable и ConcurrentHashMap? Middle
HashMap — не потокобезопасна, допускает один null-ключ и null-значения. Hashtable — устаревшая, все методы synchronized, null запрещён. ConcurrentHashMap — потокобезопасная с…
- Что происходит в HashMap при коллизии ключей? Middle
Коллизии кладутся в один bucket; HashMap ищет нужный ключ через equals, а длинную цепочку (≥8 при таблице ≥64) превращает в красно-чёрное дерево.
- Чем volatile отличается от synchronized? Middle
volatile — видимость и порядок для одной переменной без блокировки. synchronized — видимость плюс взаимное исключение: блок целиком выполняется одним потоком, поэтому составные…
- Чем Comparable отличается от Comparator и что значит согласованность порядка с equals? Middle
Comparable — естественный порядок, который задаёт сам класс (compareTo), один. Comparator — внешний порядок, их может быть сколько угодно, комбинируются через…
- Какое свойство LinkedHashMap отличает его от HashMap? Middle
LinkedHashMap — HashMap плюс двусвязный список записей: обход в порядке вставки (по умолчанию) или в порядке доступа (accessOrder = true).
- Чем IO отличается от NIO? Middle
IO (java.io) — потоки байт и символов, блокирующие: чтение держит поток, модель «поток на соединение». NIO (java.nio) — каналы и буферы, неблокирующий режим и Selector: один поток…
- Зачем нужен serialVersionUID? Middle
serialVersionUID — версия класса для встроенной сериализации. При несовпадении версии в потоке и у локального класса — InvalidClassException. Если не объявить, JVM вычислит её из…
- Как правильно использовать Optional? Middle
Optional — тип возвращаемого значения «результата может не быть», видимый в сигнатуре. Распаковывают через map, flatMap, filter, orElseGet, orElseThrow, а не isPresent() + get()…
- Чем map, flatMap и filter отличаются в Stream API? Middle
map — один элемент → один элемент (преобразование). flatMap — один элемент → поток элементов, все потоки разворачиваются в один. filter — оставляет элементы, удовлетворяющие…
- Чем LocalDateTime отличается от ZonedDateTime? Middle
LocalDateTime — дата и время без зоны: «15 марта, 09:00» неизвестно где. ZonedDateTime — с ZoneId и правилами перехода на летнее время: конкретный момент. Instant — момент на…
- В чём опасность ThreadLocal в пуле потоков? Middle
Поток в пуле переиспользуется: значение ThreadLocal, не очищенное после задачи, протекает в следующую задачу (чужой пользователь, транзакция) и удерживает память. Правило: try {…
- Что такое deadlock и как его предотвращать? Middle
Deadlock — циклическое ожидание: поток A держит замок 1 и ждёт замок 2, поток B держит 2 и ждёт 1. Предотвращают единым порядком захвата, tryLock с таймаутом и откатом, короткими…
- Чем различаются CountDownLatch, CyclicBarrier и Semaphore? Middle
CountDownLatch — одноразовое ожидание N событий: дошёл до нуля — открыт навсегда. CyclicBarrier — переиспользуемая точка встречи N потоков между раундами. Semaphore — ограничение…
- Что такое class loader и как работает делегирование загрузки классов? Middle
ClassLoader находит байт-код и превращает его в класс. Иерархия: Bootstrap (ядро JDK) → Platform (модули платформы) → Application (classpath). Модель parent-first: запрос сначала…
- Какой инструмент обычно используют для корректных Java microbenchmarks? Middle
JMH (Java Microbenchmark Harness) от разработчиков OpenJDK: учитывает прогрев, форки JVM, устранение мёртвого кода, свёртку констант, статистику по итерациям.
- Реализуй потокобезопасный счётчик Counter с методами increment() и get(). Middle
Проще всего — AtomicInteger: incrementAndGet() и get(), без блокировок. Альтернатива — synchronized на обоих методах (важно: и на чтении тоже, иначе нет видимости).
- Почему int v = flag ? map.get(key) : 0 (map.get может вернуть null) способно бросить NPE? Middle
Если одна ветвь тернарного оператора int, а другая Integer, тип всего выражения — int: обёрточная ветвь распаковывается, и null даёт NPE, хотя код выглядит безопасным.
- Чем int[] на миллион чисел выгоднее List<Integer> того же размера? Middle
int[] — сплошной блок ~4 МБ. List<Integer> — миллион отдельных объектов Integer (16 байт каждый) плюс массив ссылок: в 4–5 раз больше памяти, нагрузка на GC и промахи кэша при…
- Почему стек реализуют через ArrayDeque, а не java.util.Stack? Middle
Стек и очередь в одном потоке — ArrayDeque (кольцевой массив, O(1) по краям, данные подряд). Stack наследует Vector: synchronized на каждой операции и доступ по индексу в середину…
- В каком порядке выдаёт элементы итерация (for-each) по PriorityQueue? Middle
Итерация по PriorityQueue не отсортирована: куча гарантирует только «родитель ≤ детей». Отсортированный порядок даёт лишь повторный poll().
- Какая алгоритмическая сложность операций PriorityQueue (бинарной кучи)? Middle
offer и poll — O(log n) (просеивание вверх и вниз), peek — O(1) (корень), remove(Object) и contains — O(n) (линейный поиск).
- Какое ограничение Future решает CompletableFuture? Middle
Future — дескриптор результата с единственным способом получить значение: блокирующий get(). CompletableFuture позволяет описать цепочку продолжений (thenApply, thenCompose…
- Чем thenCompose отличается от thenApply в CompletableFuture? Middle
thenApply — как map: функция значение → значение. thenCompose — как flatMap: функция значение → новый CompletableFuture, результат «разворачивается». Без thenCompose получилось бы…
- Каков компромисс трёх базовых алгоритмов GC: mark-sweep, mark-compact, copying? Middle
Mark-sweep — пометить живых, освободить остальное: быстро, но фрагментация. Mark-compact — плюс уплотнение живых: нет фрагментации, но перемещение дорого. Copying — копировать…
- Что показывают метрики allocation rate и promotion rate? Middle
Allocation rate — сколько МБ/с приложение создаёт объектов: чем выше, тем чаще minor GC. Promotion rate — сколько МБ/с переезжает в старое поколение: чем выше, тем чаще old/full…
- Чем this внутри лямбды отличается от this внутри анонимного класса? Middle
В лямбде this — окружающий объект: она не вводит своей области видимости. В анонимном классе this — сам анонимный объект, и его поля могут перекрывать внешние. Лямбда…
- Почему лямбда может захватывать только effectively final локальные переменные? Middle
Лямбда захватывает значение локальной переменной (копию), а не ячейку: локальная переменная живёт в кадре стека и исчезает вместе с методом, а лямбда может жить дольше и…
- Чем collect отличается от reduce при сборке стрима? Middle
reduce — неизменяемая свёртка: из двух значений получается новое (сумма, максимум). collect — изменяемая свёртка: элементы накапливаются в один контейнер (список, карта…
- Что произойдёт в Collectors.toMap, если два элемента дают одинаковый ключ, а merge-функция не передана? Middle
IllegalStateException: Duplicate key. При возможных дубликатах передают третий аргумент — функцию слияния: (a, b) -> a, сумма, конкатенация.
- Как одним коллектором получить «количество элементов в каждой группе»? Middle
groupingBy(classifier, counting()) — downstream-коллектор counting сворачивает каждую группу в число (Long).
- Чем switch-выражение (case L -> …) надёжнее старого switch? Middle
Стрелочный case L -> не проваливается и не требует break; switch-выражение возвращает значение (для блока — yield); по enum и sealed-типам компилятор проверяет полноту — забытый…
- Чем Instant и LocalDateTime отличаются и когда брать Duration, а когда Period? Middle
Instant — момент на шкале (UTC, от эпохи); LocalDateTime — дата и время без зоны, моментом не является. Duration — машинное время в секундах и наносекундах, Period — календарные…
- Что требуется, чтобы класс был ПО-НАСТОЯЩЕМУ неизменяемым? Middle
Рецепт: все поля private final, нет сеттеров и других мутаторов, запрет наследования (final-класс или приватный конструктор с фабриками), защитные копии изменяемых данных на входе…
- Конструктор сохранил переданный List по ссылке (this.items = items). Почему объект всё равно изменяем? Middle
Поле хранит чужую ссылку: вызывающий меняет список снаружи, и «неизменяемый» объект меняется. final запрещает переприсвоить поле, но не менять содержимое. Нужна защитная копия на…
- Почему про immutable-объект говорят «потокобезопасен без синхронизации»? Middle
Модель памяти гарантирует: если все поля final и this не утёк из конструктора, любой поток, получивший ссылку на готовый объект, увидит поля проинициализированными — без…
- Как в immutable-дизайне моделируют «изменение» и снижают его цену? Middle
«Изменение» — новый объект: методы withX возвращают копию с одним изменённым полем. Для частых правок — изменяемый Builder, отдающий неизменяемый результат, или…
- Чего record НЕ делает за вас при проектировании неизменяемого носителя данных? Middle
Record делает компоненты private final и генерирует конструктор, аксессоры, equals, hashCode, toString, но не делает защитных копий: изменяемый компонент (List, массив, Date)…
- В коде расчёта комиссии есть метод с цепочкой if по типу платежа, и при добавлении каждого нового способа оплаты приходится править этот метод и ещё три похожих. Какой принцип SOLID нарушен в первую очередь? Middle
Open/Closed Principle: новое поведение требует правки существующего кода, а не добавления нового. Растущая цепочка if или switch по типу, повторённая в нескольких местах, …
- Что такое Liskov Substitution Principle и что обязан соблюдать подтип? Middle
Подтип должен быть подставим вместо базового типа без сюрпризов для вызывающего: не усиливать предусловия, не ослаблять постусловия, сохранять инварианты, не бросать новых…
- Сервис получает через конструктор зависимость типа PostgresOrderRepository (конкретный класс), которую внедряет Spring. Что здесь верно? Middle
DI есть, DIP нарушен: зависимость приходит снаружи (техника внедрения), но сервис зависит от конкретного класса инфраструктуры, а не от абстракции. DIP — принцип: верхний уровень…
- Что утверждает Interface Segregation Principle? Middle
Клиенты не должны зависеть от методов, которыми не пользуются: лучше несколько узких интерфейсов под роли, чем один толстый. Толстый интерфейс создаёт ложную связанность, а…
- Два метода расчёта скидки — для розницы и для опта — сегодня содержат идентичный код, но правила задают разные владельцы и они уже расходились в прошлом. Что правильнее сделать? Middle
Оставить дублирование: совпал код, но не знание. Правила меняются по разным причинам и разными владельцами — объединение создаст управляющую связанность: первое расхождение даст…
- Что верно про YAGNI? Middle
YAGNI — не строить под несуществующие требования. Цена преждевременной фичи: постройка, задержка нужного, сопровождение лишнего кода и исправление, если угадали неверно. На тесты…
- Какой из фрагментов нарушает закон Деметры? Middle
Нарушение — путешествие по графу чужих объектов: order.getCustomer().getAddress().getCity().getName() фиксирует в вызывающем коде всю структуру, и любое изменение по пути его…
- Что верно про связность (cohesion) и связанность (coupling)? Middle
Связность (cohesion) — насколько элементы модуля служат одной задаче: хотим высокую. Связанность (coupling) — насколько модуль завязан на устройство других: хотим низкую.
- Что такое anemic domain model, чем она плоха и когда всё-таки допустима? Middle
Анемичная модель: сущности — мешки геттеров и сеттеров, вся логика в сервисах. Снаружи ООП, внутри процедурный код: инварианты никто не охраняет, одно правило дублируется по…
- Чем Integer.valueOf(127) отличается от паттерна Factory Method по GoF? Middle
Factory Method (GoF) построен на наследовании: базовый класс объявляет метод создания, а какой продукт создать — решает подкласс. Integer.valueOf — статическая фабрика (идиома…
- Какие преимущества даёт статическая фабрика по сравнению с публичным конструктором? Middle
Три плюса из Effective Java: имя (of, copyOf, ofNullable — различимы, в отличие от конструкторов с одной сигнатурой), не обязана создавать новый объект (кэш, синглтон), может…
- Почему паттерн Builder особенно удобен при создании неизменяемых объектов? Middle
У неизменяемого объекта без билдера два плохих варианта: сеттеры (и он уже изменяем) или конструктор с длинным списком однотипных аргументов. Builder собирает состояние по…
- Что отличает Abstract Factory от обычной фабрики? Middle
Abstract Factory создаёт семейство связанных объектов, согласованных между собой, так что клиент не смешает объекты разных семейств. Одна фабрика одного продукта — это ещё не…
- Чем поверхностное копирование отличается от глубокого и как правильно копировать объекты в современной Java? Middle
Поверхностная копия копирует значения полей — то есть ссылки: вложенный изменяемый список общий у оригинала и копии. Глубокая — копирует весь граф. clone() — неудачный дизайн…
- По какому признаку проще всего отличить Adapter от Decorator и Proxy? Middle
По интерфейсу: адаптер меняет интерфейс (InputStreamReader превращает байтовый поток в символьный), декоратор и прокси сохраняют его. Механизм у всех трёх один — композиция и…
- Какой паттерн лежит в основе конструкции new BufferedInputStream(new GZIPInputStream(new FileInputStream(file)))? Middle
Decorator: каждая обёртка добавляет один аспект (буферизацию, распаковку) и остаётся тем же InputStream. Комбинацию выбирает клиент во время выполнения — без взрыва числа…
- Spring оборачивает бины в прокси, чтобы работали @Transactional и @Cacheable. Какие практические следствия из этого вытекают? Middle
Прокси перехватывает только внешние вызовы: this.method() внутри класса идёт мимо прокси — аннотация не сработает. CGLIB не проксирует final-классы и final-методы, JDK-прокси…
- Что произойдёт при вызове add на списке, полученном из Arrays.asList(array)? Middle
UnsupportedOperationException: Arrays.asList — адаптер над массивом фиксированного размера. add и remove не поддержаны, а set пишет прямо в массив (и изменения массива видны в…
- Какой паттерн реализуют SLF4J и JdbcTemplate по отношению к тому, что они скрывают? Middle
Facade — простой вход в сложную подсистему. SLF4J — Simple Logging Facade for Java. JdbcTemplate скрывает ритуал JDBC: соединение, statement, обработка SQLException, закрытие…
- Чем паттерн Proxy отличается от Decorator, если у обоих тот же интерфейс, что и у обёрнутого объекта? Middle
Структурно почти одинаковы, различие — в намерении: декоратор добавляет поведение, и цепочку собирает клиент; прокси управляет доступом к объекту (ленивое создание, права, кэш…
- Какой паттерн представляет java.util.Comparator? Middle
Strategy: алгоритм сравнения передаётся снаружи, сортировка при этом не меняется.
- В чём принципиальная разница между Template Method и Strategy? Middle
Template Method — наследование на этапе компиляции: скелет алгоритма в базовом классе, подкласс заполняет шаги. Strategy — композиция во время выполнения: алгоритм передаётся…
- Что верно про реализацию паттерна Observer в современной Java? Middle
java.util.Observable устарел с Java 9. Современные формы: ApplicationEventPublisher и @EventListener в Spring, реактивные потоки (Flow, Reactor), брокеры сообщений. Подводные…
- Какой паттерн реализуют цепочка сервлетных фильтров и фильтр-цепочка Spring Security? Middle
Chain of Responsibility: запрос идёт по звеньям, и каждое решает, обработать ли его и передавать ли дальше (chain.doFilter). Возможность прервать цепочку — отличие от декоратора…
- State и Strategy структурно почти одинаковы. Что их различает? Middle
Кто управляет подстановкой: стратегию выбирает клиент снаружи, и она обычно не меняется; состояние объект меняет сам в ответ на события, и переходы — часть его логики.
- Поток пытается войти в synchronized-блок, занятый другим потоком. В каком состоянии он находится? Middle
BLOCKED — ожидание входа в занятый монитор synchronized. Шесть состояний: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
- Что верно про прерывание потока через interrupt()? Middle
interrupt() — просьба, а не приказ: выставляет флаг; блокирующие sleep, wait, join бросают InterruptedException и сбрасывают флаг. Поток проверяет флаг сам и завершается в…
- Что верно про daemon-потоки? Middle
JVM завершается, когда остались только daemon-потоки; они обрываются без выполнения finally. Флаг ставится до start(), иначе IllegalThreadStateException.
- Почему фабрики из класса Executors считают опасными в production-коде? Middle
Скрытые неограниченные ресурсы: newFixedThreadPool — неограниченная очередь (задачи копятся до OutOfMemoryError, наружу не идёт никакого отказа), newCachedThreadPool …
- Сервис в основном ходит по сети: на каждую задачу примерно 90% времени — ожидание ответа и 10% — вычисления. Как выбрать размер пула потоков? Middle
IO-bound: ядра × (1 + W/C), где W — ожидание, C — вычисления; при 90/10 — около 10 × ядер. CPU-bound — примерно по числу ядер. Это ориентир: реальный предел часто задаёт внешний…
- Задача, отправленная в пул через submit(), бросает RuntimeException, но в логах ничего нет. Почему? Middle
submit() прячет исключение в Future: оно появится только при get() в ExecutionException. Если результат никто не запрашивает — ошибка исчезает бесследно. execute() пропускает…
- Какие пары действий образуют отношение happens-before? Middle
Happens-before — гарантия, что результаты A видны в B. Пары: порядок внутри потока, unlock → последующий lock того же монитора, запись volatile → последующее чтение того же поля…
- Нужно ограничить число одновременных обращений к внешнему API десятью, не ограничивая при этом число рабочих потоков. Какой примитив подходит? Middle
Semaphore с десятью разрешениями: acquire перед вызовом, release в finally. Он ограничивает число одновременных доступов к ресурсу, не трогая число потоков.
- Можно ли переиспользовать CountDownLatch после того, как счётчик дошёл до нуля? Middle
Нет: дошедший до нуля CountDownLatch открыт навсегда, метода сброса нет. Для повторяющихся раундов — CyclicBarrier или Phaser; либо новый latch на каждый раунд.
- В коде вызывается semaphore.acquire(), затем работа с ресурсом, затем semaphore.release() в конце метода. Что здесь опасно? Middle
release не в finally: исключение навсегда съедает разрешение. С каждым сбоем параллелизм падает на единицу, пока система не встанет без единой записи в логе.
- Что верно про практическое применение виртуальных потоков? Middle
Не пулить (поток на задачу), применять для блокирующего ввода-вывода, помнить, что ThreadLocal на миллионах потоков дорог, и ограничивать доступ к внешним ресурсам семафором — пул…
- Что происходит с виртуальным потоком, когда он выполняет блокирующий сетевой вызов? Middle
Unmount: стек виртуального потока (continuation) сохраняется в куче, несущий поток освобождается для других задач. Когда данные пришли — mount обратно, возможно на другой несущий…
- На какой гипотезе построено разделение кучи на поколения? Middle
Слабая гипотеза о поколениях: почти все объекты умирают молодыми, а пережившие несколько сборок живут долго. Отсюда молодое поколение с копирующим сборщиком: цена сборки…
- Зачем в молодом поколении две области Survivor, а не одна? Middle
Копирующему сборщику нужна пустая область назначения: живые из Eden и занятого Survivor копируются в свободный Survivor, после чего Eden и бывший Survivor очищаются целиком, а…
- В приложении участились длинные паузы full GC, при этом старое поколение почти всегда заполнено. О чём это говорит? Middle
Живых данных больше, чем помещается. Смотрят на занятость после каждого full GC: ползёт вверх — утечка, держится высоко, но стабильно — кучи мало под рабочий набор. Лечат причину…
- Что верно про типы ссылок в Java? Middle
Strong — не собирается, пока достижим. Soft — очищается при нехватке памяти (кэш, который не жалко). Weak — на ближайшей сборке, если нет сильных ссылок (WeakHashMap, метаданные)…
- Что относится к GC roots — корням достижимости? Middle
Корни — точки начала обхода: локальные переменные и параметры в стеках живых потоков, статические поля загруженных классов, JNI-ссылки, сами активные потоки и удерживаемые…
- Почему finalize() признан неудачным механизмом и что использовать вместо него? Middle
finalize не гарантирует ни вызова, ни времени, замедляет сборку (объект переживает лишний цикл) и может «воскресить» объект. Устарел в Java 9, помечен к удалению в Java 18…
- Нужна структура с быстрым поиском по ключу, которая при обходе отдаёт элементы в порядке их добавления. Что выбрать? Middle
LinkedHashMap: поиск по ключу O(1) и обход в порядке добавления.
- Что верно про неизменяемые и защитные коллекции? Middle
List.of и List.copyOf — настоящие неизменяемые коллекции, null запрещён. Collections.unmodifiableList — представление: через исходную ссылку список по-прежнему меняется. Объекты…
- Почему добавление в конец ArrayList считается амортизированно O(1), хотя иногда требует копирования всего массива? Middle
Ёмкость растёт в 1,5 раза: копирования всё реже, сумма копирований на n вставок — геометрическая прогрессия, то есть O(n). На одну вставку — константа в среднем, хотя отдельная…
- Сколько стоит удаление элемента из середины ArrayList и почему? Middle
O(n): хвост сдвигается влево через System.arraycopy, последняя ячейка обнуляется. Удаление в цикле — квадратичная работа.
- Что верно про управление ёмкостью ArrayList? Middle
Ёмкость растёт, но не уменьшается сама; clear() обнуляет ссылки, а массив остаётся прежнего размера. Пустой ArrayList без аргументов выделяет массив лениво — при первом добавлении…
- Почему утверждение «вставка в середину LinkedList работает за O(1)» вводит в заблуждение? Middle
O(1) — только перецепление ссылок. Чтобы вставить по индексу, сначала нужно дойти до позиции — O(n). Итого add(i, x) линейный и у LinkedList, и у ArrayList.
- Почему ArrayList обычно обходит LinkedList даже там, где асимптотика формально в пользу связного списка? Middle
Локальность данных: массив лежит подряд и попадает в кэш процессора блоками, узлы LinkedList разбросаны по куче — промах кэша на каждом шаге. Плюс узел — отдельный объект с…
- Нужна очередь FIFO внутри одного потока. Что выбрать по умолчанию? Middle
ArrayDeque: кольцевой массив, offer и poll — O(1), без узла на элемент и промахов кэша.
- Как получить LRU-кэш на базе LinkedHashMap? Middle
new LinkedHashMap<>(cap, 0.75f, true) (accessOrder) + переопределённый removeEldestEntry, возвращающий size() > max. Get переносит запись в конец, самая давно неиспользуемая — в…
- Какой ценой LinkedHashMap поддерживает предсказуемый порядок обхода по сравнению с HashMap? Middle
Цена — две дополнительные ссылки на запись и поддержка списка при вставке и удалении. get и put остаются O(1); обход даже быстрее — по списку, а не по всем корзинам.
- Что произойдёт при обходе LinkedHashMap, созданного с accessOrder = true, если во время итерации вызвать get() по существующему ключу? Middle
В режиме accessOrder даже get переносит запись в конец — это структурная модификация, итератор бросит ConcurrentModificationException.
- Как устроен HashSet внутри? Middle
HashSet — это HashMap: элементы — ключи, значение — общий объект-заглушка. LinkedHashSet построен на LinkedHashMap, TreeSet — на TreeMap.
- В TreeSet добавили два объекта, для которых equals возвращает false, но компаратор считает их равными. Что произойдёт? Middle
Второй объект не будет добавлен: TreeSet считает элементы равными, если сравнение даёт 0, equals не вызывается.
- Объект добавили в HashSet, после чего изменили у него поле, участвующее в hashCode. Что теперь вернёт contains для этого же объекта? Middle
Скорее всего false: объект лежит в корзине по старому хешу, а ищут по новому. При этом в итерации он останется — и удалить его через remove уже не получится.
- В цикле for-each по списку вызывается list.remove(element). Что произойдёт? Middle
ConcurrentModificationException — даже в одном потоке: for-each идёт через итератор, а list.remove меняет коллекцию мимо него; итератор сверяет modCount и падает.
- Какие способы удалить элементы по условию во время обхода коллекции корректны? Middle
Корректно: removeIf, явный Iterator.remove(), проход по индексам с конца. Удаление в for-each — CME, по индексам вперёд — пропуск элементов.
- Чем ListIterator отличается от обычного Iterator? Middle
ListIterator — только для списков: ход в обе стороны (hasPrevious, previous), индексы (nextIndex), изменение на месте — set и add.
- Нужно быстро находить ближайшую запись с ключом не больше заданного и выбирать все записи в диапазоне дат. Какая структура подходит? Middle
TreeMap как NavigableMap: floorKey/ceilingKey/lowerKey/higherKey и subMap, headMap, tailMap за O(log n). Хеш-таблица порядок не хранит.
- Что произойдёт при попытке положить null-ключ в TreeMap? Middle
NullPointerException: TreeMap сравнивает ключи, а null сравнить естественным порядком нельзя. HashMap допускает один null-ключ.
- Какие требования входят в контракт equals? Middle
Рефлексивность (a.equals(a)), симметричность, транзитивность, согласованность (повторные вызовы дают одно и то же) и a.equals(null) == false. Самое частое нарушение …
- Метод принимает StringBuilder и внутри выполняет sb.append("x"), а затем sb = new StringBuilder(). Что увидит вызывающий код? Middle
Вызывающий увидит добавленный символ, но не новый объект: Java всегда передаёт по значению, а для ссылочных типов значение — копия ссылки. Мутация объекта по копии видна всем…
- У списка есть перегрузки remove(int index) и remove(Object o). Что сделает list.remove(1) для List<Integer>? Middle
Удалит элемент с индексом 1: перегрузка выбирается на компиляции, и remove(int) подходит без упаковки — на первой фазе подбора. Удалить значение 1 …
- Что верно про varargs? Middle
Varargs — сахар над массивом: внутри параметр — обычный массив, он единственный и последний, без аргументов приходит пустой массив, а не null. Каждый вызов выделяет массив …
- В try-with-resources исключение бросают и тело блока, и метод close(). Какое исключение получит вызывающий код? Middle
Наверх идёт исключение из тела — оно о настоящей причине. Исключение из close() прикрепляется к нему как suppressed (getSuppressed(), видно в стектрейсе). Ручной try/finally терял…
- Чем интерфейс AutoCloseable отличается от Closeable? Middle
AutoCloseable (Java 7) — для любых ресурсов, close() бросает Exception. Closeable (java.io, старше) — его наследник под ввод-вывод: close() бросает IOException и обязан быть…
- Код открывает соединение, затем в том же try создаёт из него statement, и оба объявлены в скобках try-with-resources. В каком порядке они закроются? Middle
Сначала statement, потом соединение — в обратном порядке объявления, как раскручивается стек: зависимый ресурс закрывается раньше того, из которого получен.
- Почему List<String> нельзя присвоить переменной типа List<Object>? Middle
Дженерики инвариантны: если бы List<Object> objs = strings компилировалось, через objs можно было бы положить Integer, а потом получить ClassCastException при чтении из списка…
- Что можно делать со списком, объявленным как List<? extends Number>? Middle
Читать как Number можно, добавлять нельзя ничего, кроме null: за ссылкой может быть List<Integer> или List<Double>, и компилятор не знает какой. Симметрично List<? super Integer>…
- Метод должен перекладывать элементы из источника в приёмник. Какая сигнатура правильна по правилу PECS? Middle
void copy(List<? super T> dest, List<? extends T> src): источник производит — extends, приёмник потребляет — super. Так объявлен Collections.copy.
- Что верно про record в Java? Middle
Компилятор генерирует private final поля, канонический конструктор, аксессоры (name(), без get), equals, hashCode, toString по всем компонентам. Record неявно final, наследует…
- Когда record — неудачный выбор? Middle
Record прозрачен: компоненты — публичный контракт. Не подходит для изменяемых сущностей со скрытым представлением и охраняемыми инвариантами, для JPA-сущностей (нужны конструктор…
- Что произойдёт, если объявить record с полем-массивом и сравнить два таких объекта с одинаковым содержимым массива? Middle
equals вернёт false: сгенерированный equals сравнивает компоненты их собственным equals, а у массива это сравнение по ссылке. hashCode тоже будет по идентичности, toString…
- Какое главное преимущество даёт sealed-иерархия при использовании switch с pattern matching? Middle
Закрытый список наследников делает проверку полноты switch работой компилятора: не нужен default, а новый подтип — ошибка компиляции во всех switch, которые его не обрабатывают…
- Что обязан сделать наследник sealed-класса? Middle
Наследник sealed-класса обязан: быть в permits (или в том же файле, если permits опущен), объявить себя final, sealed или non-sealed, лежать в том же модуле (вне модулей — в том…
- Что даёт pattern matching в instanceof по сравнению с классической проверкой? Middle
Проверка и приведение объединяются: if (o instanceof String s) сразу даёт переменную s нужного типа. Нет дублирующего приведения, которое может разойтись с проверкой.
- Почему встроенную Java-сериализацию считают небезопасной и устаревшей? Middle
Безопасность: десериализация сама создаёт объекты классов из потока и вызывает их методы восстановления до любой проверки — из классов в classpath собирают гаджет-цепочку и…
- Что произойдёт с полем, помеченным transient, при сериализации и последующей десериализации? Middle
Поле не попадёт в поток, а после восстановления получит значение по умолчанию для типа (null, 0, false) — инициализатор поля и конструктор не выполняются.
- Чем Externalizable отличается от Serializable? Middle
Externalizable — полный ручной контроль: формат пишут writeExternal и readExternal, нужен публичный конструктор без аргументов (вызывается при восстановлении). Serializable …
- Что означают позиция, лимит и ёмкость у ByteBuffer, и что делает flip()? Middle
Ёмкость — размер буфера, позиция — курсор следующего чтения или записи, лимит — граница доступных данных. flip() ставит лимит на текущую позицию и обнуляет позицию — переключает…
- Как виртуальные потоки изменили типичный выбор между блокирующим IO и неблокирующей моделью на Selector? Middle
Главный довод за event loop — дороговизна потока — снят: виртуальный поток дешёв и при блокировке отцепляется от несущего. Можно писать блокирующий читаемый код при высокой…
- Что верно про JIT-компиляцию в HotSpot? Middle
Код сначала интерпретируется, горячие методы компилирует C1 (быстро, с профилированием), затем C2 (агрессивные оптимизации по профилю). Оптимизации спекулятивны: встраивание по…
- Почему java.util.Stack, унаследованный от Vector, считают ошибкой дизайна? Middle
«Стек — это вектор» неверно: наследование выставило наружу get(i), add(i, x), remove(i) — операции, разрушающие инвариант LIFO. Правильно — композиция: список внутри, наружу…
- Класс сделал все поля private и добавил к каждому геттер и сеттер. Достигнута ли инкапсуляция? Middle
Нет: инкапсуляция — это сокрытие состояния за операциями, которые держат инварианты. Сеттер на каждое поле позволяет привести объект в невозможное состояние: баланс отрицательный…
- Что верно про полиморфизм в Java? Middle
Динамически (по реальному классу объекта) выбираются только переопределённые методы экземпляра. Статические методы скрываются, а не переопределяются: вызов определяется…
- В каком порядке выполняется инициализация при создании объекта подкласса? Middle
Один раз при инициализации класса: static-поля и static-блоки — родитель, затем наследник. На каждый new: конструктор наследника сразу вызывает super(), отрабатывают поля и блоки…
- Класс реализует два несвязанных интерфейса, в каждом из которых есть default-метод с одинаковой сигнатурой. Что произойдёт? Middle
Ошибка компиляции: класс обязан переопределить метод. Выбрать реализацию можно явно: A.super.method().
- Ради чего в Java 8 добавили default-методы интерфейсов? Middle
Эволюция API без слома совместимости: добавление метода в интерфейс раньше ломало все реализации, а Collection и Iterable реализованы в бесчисленных библиотеках. Без default не…
- Что верно про иерархию Throwable? Middle
Throwable → Error и Exception; RuntimeException — наследник Exception. Checked = Exception минус RuntimeException. Error (OutOfMemoryError, StackOverflowError) — среда в нерабочем…
- Метод бросает исключение внутри try, а в блоке finally стоит return. Что получит вызывающий? Middle
Нормальный возврат: return в finally перекрывает исходный выход и проглатывает исключение — сбой бесследно исчезает. Так же действуют break и continue.
- Почему вызов wait() принято помещать в цикл while, а не в if? Middle
Пробуждение не гарантирует, что условие выполнено: возможны ложные пробуждения (spurious wakeup), а между notify и захватом монитора другой поток мог снова изменить состояние…
- На каких объектах не следует синхронизироваться? Middle
Не синхронизироваться на разделяемых или подменяемых объектах: строковых литералах (интернированы), Integer и других обёртках (кэш значений), публичном this, изменяемом поле…
- Чем LongAdder выигрывает у AtomicLong при высокой конкуренции и в чём его ограничение? Middle
LongAdder разносит счёт по нескольким ячейкам: потоки не бьются за одну переменную, CAS не промахивается, кэш-линия не скачет между ядрами. Итог — сумма ячеек, а не мгновенно…
- Какие возможности даёт ReentrantLock, недоступные при использовании synchronized? Middle
ReentrantLock добавляет tryLock (с таймаутом), lockInterruptibly, справедливый режим и несколько Condition. Цена — освобождение вручную: lock() перед try, unlock() в finally.
- В parallel stream выполняется обращение к внешнему HTTP-сервису. Почему это опасно для всего приложения? Middle
Parallel stream выполняется в общем ForkJoinPool.commonPool — одном на JVM, размером «ядра − 1». Блокирующий HTTP-вызов занимает его потоки, и встают все parallel stream и…
- В каких случаях parallel stream, скорее всего, не даст выигрыша или окажется медленнее последовательного? Middle
Выигрыша нет, когда мало данных или дешёвая операция (N × Q мало), источник плохо делится (LinkedList, Stream.iterate, итератор), есть сохранение порядка (forEachOrdered, limit…
- Чем различаются exceptionally, handle и whenComplete у CompletableFuture? Middle
exceptionally — только при ошибке, подменяет результат. handle — вызывается всегда, получает значение и исключение и возвращает новый результат. whenComplete — побочный эффект…
- Когда уместен CopyOnWriteArrayList? Middle
Каждая запись копирует весь массив — оправдано только при подавляющем преобладании чтений и небольшом размере: реестр слушателей, конфигурация.
- Что верно про ёмкость и load factor в HashMap? Middle
Ёмкость — степень двойки (индекс через hash & (n-1) вместо остатка), при превышении ёмкость × 0.75 таблица удваивается, а цепочка становится деревом только при длине ≥ 8 и ёмкости…
- Почему ArrayDeque не допускает null-элементов? Middle
null зарезервирован как сигнал «элемента нет»: poll и peek возвращают null для пустой очереди. Если бы null хранился, ответ стал бы неоднозначным.
- Что верно про стек и кучу в JVM? Middle
Стек — у каждого потока свой (-Xss): кадры вызовов, локальные примитивы значением и ссылки. Куча — общая (-Xmx): сами объекты. Переполнение стека — StackOverflowError, нехватка…
- Java-приложение запускают в контейнере с лимитом памяти. Как правильно задать размер кучи? Middle
Задавать кучу долей от лимита: -XX:MaxRAMPercentage=70–75, оставляя запас на память вне кучи (Metaspace, стеки, кодовый кэш, direct-буферы, GC). -Xmx, равный лимиту, приводит к…
- Что невозможно из-за стирания типов? Middle
В рантайме параметра типа нет, поэтому нельзя: new T(), new T[n], instanceof List<String>, статическое поле типа T, перегрузка m(List<String>) и m(List<Integer>) (одинаковая…
- Зачем в сигнатуре пишут <T extends Comparable<T>>? Middle
Граница сужает допустимые типы и открывает методы границы: без неё T — просто Object, и compareTo вызвать нельзя. После стирания T заменяется верхней границей — Comparable.
- Чем опасно использование raw type, например List вместо List<String>? Middle
Raw type выключает проверку дженериков для всего выражения: в список строк можно положить число, а ClassCastException появится далеко — при чтении, где компилятор вставил…
- Зачем в JDK помимо Function<T,R> существуют IntFunction, ToIntFunction и IntPredicate? Middle
Дженерики работают только со ссылочными типами, поэтому Function<Integer, Integer> упаковывает и распаковывает значения на каждом вызове. Специализации (IntFunction…
- Переменной присвоили Stream, вызвали count(), а затем на той же переменной вызвали forEach(). Что произойдёт? Middle
IllegalStateException: stream has already been operated upon or closed. Стрим — одноразовый конвейер над источником, а не хранилище данных.
- В конвейере стоят filter и map. Почему порядок filter перед map обычно предпочтительнее обратного? Middle
Элементы идут по конвейеру по одному: дорогое преобразование до фильтра выполняется и для отбрасываемых элементов. Чем раньше отсеять, тем меньше работы.
- Функция значения в Collectors.toMap вернула null для одного из элементов. Что произойдёт? Middle
NullPointerException, хотя HashMap null-значения допускает: коллектор использует merge, а он по контракту запрещает null — не отличить от отсутствия ключа.
- Чем orElse отличается от orElseGet? Middle
orElse(value) — аргумент вычисляется всегда, даже если значение есть (обычный порядок вычисления аргументов). orElseGet(supplier) — поставщик вызывается только при отсутствии.
- Какие способы применения Optional считаются антипаттернами? Middle
Антипаттерны: Optional как поле (не сериализуем, лишняя аллокация), как параметр (перекладывает проблему на вызывающего), голый get() без проверки, isPresent + get вместо map и…
- Статическое поле SimpleDateFormat используется из нескольких потоков, и изредка возвращаются неверные даты. В чём причина и что делать? Middle
SimpleDateFormat хранит изменяемый Calendar внутри: параллельные вызовы затирают состояние друг друга — неверные даты или исключения, причём только под нагрузкой. Замена …
- Почему чтение файла по одному байту через FileInputStream радикально медленнее, чем через BufferedInputStream? Middle
Дорог не байт, а системный вызов с переходом в ядро. Чтение по байту из FileInputStream — по вызову на байт; BufferedInputStream читает блок (8 КБ) за один вызов и отдаёт байты из…
- Приложение читает файл через new FileReader(path) без указания кодировки. Чем это опасно? Middle
Кодировка по умолчанию зависела от окружения (локаль ОС): одна сборка вела себя по-разному на машине разработчика и на сервере, данные молча портились. С Java 18 по умолчанию…
- Почему в логировании предпочитают log.debug("user {} order {}", userId, orderId) вместо конкатенации строк? Middle
Отложенное форматирование: строка собирается, только если уровень включён. Конкатенация вычисляется до вызова всегда — на горячем пути с выключенным debug это лишние аллокации.
- Что такое текстовый блок и как в нём работают отступы? Middle
Многострочный литерал в тройных кавычках: JSON, SQL, HTML без экранирования и конкатенации. Результат — обычная String. Общий отступ (по самой левой строке и закрывающим кавычкам)…
- Что такое autoboxing и какие ловушки он приносит? Middle
Компилятор подставляет Integer.valueOf при упаковке и intValue при распаковке. Ловушки: == работает только внутри кэша −128…127, распаковка null — NPE, каждая упаковка вне кэша …
- Как выбираешь структуру данных под задачу? Проведи рассуждение на примере: нужно хранить сессии пользователей с быстрым поиском по id и обходом в порядке добавления. Middle
Метод: какие операции горячие и как часто → сложность каждой у кандидатов → память и конкурентность. Поиск по id + обход в порядке добавления → LinkedHashMap; при доступе из…
- В сервисе нужно сохранить момент оформления заказа и дату доставки, выбранную пользователем. Какие типы java.time возьмёшь и почему? Middle
Момент оформления — Instant (в БД timestamptz, всегда UTC): событие произошло объективно, его сравнивают и сортируют глобально. Дата доставки — LocalDate: это не момент, а выбор…
- Два потока одновременно вызывают incrementAndGet() у одного AtomicInteger. Что при этом происходит внутри и почему ни один инкремент не теряется? Middle
CAS-цикл: прочитать значение, вычислить новое и записать, только если в памяти всё ещё старое (одна атомарная инструкция процессора). Проиграл гонку — повторить с новым значением…