惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Webroot Blog
Webroot Blog
罗磊的独立博客
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
G
Google Developers Blog
WordPress大学
WordPress大学
T
Tailwind CSS Blog
U
Unit 42
B
Blog
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
Vercel News
Vercel News
博客园 - Franky
T
Tenable Blog
F
Fortinet All Blogs
P
Privacy International News Feed
P
Palo Alto Networks Blog
Security Latest
Security Latest
爱范儿
爱范儿
K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
V2EX
The Cloudflare Blog
H
Help Net Security
NISL@THU
NISL@THU
酷 壳 – CoolShell
酷 壳 – CoolShell
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
月光博客
月光博客
C
CERT Recently Published Vulnerability Notes
L
Lohrmann on Cybersecurity
Latest news
Latest news
A
Arctic Wolf
C
Cisco Blogs
宝玉的分享
宝玉的分享
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
O
OpenAI News
S
Security Archives - TechRepublic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
I
InfoQ
云风的 BLOG
云风的 BLOG
PCI Perspectives
PCI Perspectives
C
CXSECURITY Database RSS Feed - CXSecurity.com
Recorded Future
Recorded Future
V
V2EX - 技术
D
DataBreaches.Net

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
8 вопросов с java-собеса в банке: Junior отвечает за 10 секунд, Senior — за 3 минуты. Кого берут?
Java Jub · 2026-06-16 · via Все публикации подряд на Хабре

Средний

11 мин

974

Один вопрос — три ответа

Один вопрос — три ответа

Один и тот же вопрос, три глубины ответа. По ней интервьюер и считывает грейд.


Последние полгода я почти каждую неделю смотрю чужие расшифровки собеседований — присылают в личку, что-то лежит в открытых базах. Сначала ради своего канала, потом просто втянулся. И вот что в какой-то момент стало резать глаз.

Вопросы на собесах в банках от грейда к грейду почти не меняются.

«Что такое индекс» спрашивают и у стажёра, и у сеньора с десятью годами. Про equals и hashCode — тоже у всех. Про @Transactional — вообще в каждом втором интервью, кого ни возьми. Меняется не сам вопрос. Меняется глубина, на которую от тебя ждут ответ. И именно по этой глубине интервьюер за полминуты понимает твой настоящий уровень — задолго до того, как вы дойдёте до зарплаты.

Сразу оговорюсь, потому что меня за прошлую статью за это справедливо пинали: я не считал, сколько процентов народу спотыкается на каждом вопросе. Нет у меня таких цифр, и придумывать их я не стану. Зато есть сами расшифровки, где видно, как один и тот же вопрос звучит на джуне, на мидле и на сеньоре — и насколько по-разному его ждут.

Сразу про одну вещь, в которой я сам долго путался, когда раскладывал эти ответы. Граница «мидл / сеньор» проходит не там, где кажется. «Знать, как HashMap превращает список в дерево» или «как AtomicInteger работает на CAS» — это не сеньор, это крепкий мидл. Сеньор отличается не тем, что помнит больше внутренностей JDK, а тем, что видел, как это всё ломается в проде, и думает про цену решения. Дальше будет видно по каждому вопросу.

Я выбрал восемь таких вопросов. По каждому — три ответа подряд: джун, мидл, сеньор. Читайте и прикидывайте, на какой строчке заканчиваетесь лично вы. Это дешевле, чем выяснить то же самое на реальном собесе.


Чтобы было видно, о чём речь, вот тот самый «индексный» вопрос, разложенный по уровням. Дальше будет ещё семь в том же духе.

Один вопрос «что такое индекс» — три глубины ответа

Один вопрос «что такое индекс» — три глубины ответа

Где-то ниже я помечаю уровни цветом — 🟢 джун, 🟡 мидл, 🔴 сеньор, — а где история живее прозой, просто называю их по ходу. Уровни наслаиваются: мидл знает всё, что джун, плюс своё; сеньор — всё это плюс то, что приходит только с продом.


1. equals и hashCode

Баян, конечно. Но раз спрашивают везде, давайте по-честному — и без карикатур на джуна.

🟢 Джун обычно отвечает уверенно и правильно: equals — это равенство по значению, == — по ссылке; переопределил equals — переопредели и hashCode, это контракт; равные объекты обязаны вернуть равный hashCode. Генерю через IDE, Lombok или беру record. Нормальный ответ, он правда так знает.

🟡 Мидл показывает, что будет, если контракт нарушить. Переопределили только equals — и два «равных» объекта дадут разный hashCode, улетят в разные бакеты HashMap, а get() по второму ключу вернёт null, хотя элемент в карте лежит. Обратное контрактом не требуется: одинаковый хэш у разных объектов это просто коллизия, и это нормально. Сюда же правило, которое экономит нервы: hashCode нельзя строить на полях, которые потом меняются.

🔴 Сеньор говорит не про новые факты, а про то, как это спроектировать, чтобы не рвануло в реальном приложении. JPA-сущности: id генерит база, до сохранения он null, и наивный equals по id ведёт detached- и managed-объекты по-разному — Set начинает «терять» элементы между сессиями. Лечится бизнес-ключом или фиксированным hashCode. Плюс ловушка с Hibernate: ленивый прокси подменяет класс объекта, поэтому equals через getClass() ломается на прокси, и берут instanceof. Вот эта прод-боль и отличает сеньора, а не знание самого контракта.

Граница тут честная: контракт назубок знают все, а что именно отвалится в ORM — единицы. В расшифровках, кстати, у ТБанка дословно: «контракт equals и hashCode, может ли у разных объектов совпасть hashCode».


2. Как устроен HashMap

Логичное продолжение, поэтому часто идёт сразу за предыдущим.

🟢 Джун опишет верхушку: пары «ключ — значение», ключ уникален, доступ в среднем за O(1), внутри массив. TreeMap держит ключи отсортированными. Для старта достаточно, и это не стыдно.

🟡 Мидл залезает под капот — и вот это весь мидловский слой, тут нет ничего сеньорского. Массив бакетов, индекс считается как hash & (n-1), коллизии складываются в бакет списком. Load factor 0.75: заполнилось больше — resize, удвоение массива и перераскладка. С Java 8 длинный бакет (восемь элементов, когда сам массив уже не меньше 64) превращается в красно-чёрное дерево, чтобы вырожденный случай не падал в O(n); обратно в список — на шести. Перед раскладкой старшие биты хэша подмешиваются в младшие, чтобы кривой hashCode реже коллизировал. И HashMap не потокобезопасен.

🔴 Сеньор не сыплет внутренностями дальше — он выбирает инструмент и считает цену. Высокая конкуренция значит ConcurrentHashMap, и сразу оговорка, что его итератор слабосогласованный, а не fail-fast. Resize на большой мапе — это пауза на перехеширование, поэтому если размер примерно известен, мапу присайзивают через конструктор, чтобы не ловить пилу по latency. А если в ней миллионы записей с примитивами, всплывает оверхед на каждый Node, и иногда честнее специализированная коллекция.


Устройство HashMap: список и дерево

Устройство HashMap: список и дерево

Коллизии — список; при 8+ в одном бакете он становится красно-чёрным деревом. Это уровень Middle.


3. Почему String неизменяемый

Простой на вид вопрос, на котором удобно нащупать границу. И тут честно: у джуна с мидлом ответы заметно перекрываются, грань тонкая.

🟢 Джун скажет: String нельзя изменить после создания, для изменений есть StringBuilder, литералы лежат в пуле, поэтому одинаковые литералы — это один объект. 🟡 Мидл добавит механику: литералы интернируются, new String("x") всегда создаёт объект мимо пула, вернуть в пул можно через intern(); склейка двух литералов схлопывается компилятором в один, а конкатенация переменных в цикле плодит мусор — отсюда вечный совет про StringBuilder. И мидл уже отвечает на «зачем»: потокобезопасность без блокировок и hashCode, посчитанный один раз и закэшированный (поэтому String так хорош как ключ).

А вот где настоящая сеньорская грань — и это надо сказать прямо: здесь она не про новый факт, а про опыт. Сеньор вспомнит безопасность как инвариант: проверенный путь к файлу, host или фрагмент SQL нельзя подменить после валидации, иначе классический TOCTOU, и неизменяемость закрывает это бесплатно. И грабли intern() на масштабе: пул живёт в куче, но если интернировать строки из пользовательского ввода, он пухнет и начинает давить на GC — такое ловили в проде не раз. Плюс Compact Strings с Java 9, latin1 против UTF-16, что реально меняет память на сервисах, где строк миллионы.

То есть граница тут проходит не по знанию определения, а по тому, видел ли человек, как intern() или склейка в горячем цикле выстреливали на продакшене.


4. Optional

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

Ловушка первая: orElse(x) вычисляет x всегда — даже когда значение есть и x не нужен. Если за x прячется поход в базу, это лишний запрос на ровном месте. Ловушка вторая: Optional в поле сущности или DTO.

🟢 Джун про Optional знает базовое и верное: обёртка, чтобы явно показать, что значения может не быть, и не возвращать null. На первую ловушку, скорее всего, не среагирует, и это ожидаемо.

🟡 Мидл обе ловушки разруливает. orElseGet(() -> x) ленивый, в отличие от orElse; get() без проверки — это тот же NPE, только сбоку; для потенциального null нужен ofNullable, а не of, который сам кинет NPE. Знает map/flatMap/filter и orElseThrow.

🔴 Сеньор смотрит на это как на дизайн API. Optional задуман как тип возвращаемого значения, и только: он не Serializable (поле ломает сериализацию), это лишняя аллокация на горячем пути, а Optional<List<T>> — нонсенс, пустой список и так говорит «ничего нет». Поэтому в полях, параметрах и коллекциях его не держат. Разница между мидлом и сеньором тут не в знании методов, а во вкусе: где этой обёртке место в публичном контракте, а где она только мусорит.


5. counter++ и сто потоков

Самый частый практический вопрос по многопоточке. Дают код, где сто потоков по тысяче раз дёргают один счётчик, и спрашивают, будет ли в конце 100000.

🟢 Джун ответит верно по сути: нет, будет меньше, потоки мешают друг другу, это race condition, надо synchronized. Направление правильное.

🟡 Мидл объяснит, почему меньше, и это ровно его слой. counter++ — не одна операция, а три: прочитать, увеличить, записать; два потока читают одно значение, и один инкремент затирается. Чинится либо synchronized-блоком, либо AtomicInteger.incrementAndGet(). И да, мидл вполне знает, что атомик внутри на CAS: читает текущее, пытается записать новое, проверяет, что за это время никто не влез, влез — повтор по кругу, блокировки нет. Подчеркну: вот это всё ещё разговор уровня Middle, ничего сеньорского в «знаю про CAS» нет.

🔴 Сеньор начинает с того, что переформулирует задачу. Под высокой конкуренцией CAS-спин крутится вхолостую и жжёт CPU — тогда выигрывает LongAdder, который размазывает счётчик по ячейкам и складывает их лениво при чтении. Но ещё раньше сеньор спросит: а нужен ли вообще один общий счётчик? Часто можно считать локально в каждом потоке и свести в конце; иногда это вообще работа БД или Redis с атомарным инкрементом; и нужна ли точность в моменте или достаточно, чтобы значение сошлось чуть позже. «Починить counter++» — часто не та задача, которую стоило решать.


Гонка в counter++: потерянный инкремент

Гонка в counter++: потерянный инкремент

Оба потока прочитали 41, оба записали 42 — один инкремент потерян. Вот почему counter++ не атомарна.


6. volatile и happens-before

Прямое продолжение, обычно идёт сразу следом, чтобы добить тему.

🟢 Джун: volatile нужен, чтобы потоки видели актуальное значение, а не закэшированное у себя в ядре.

🟡 Мидл ставит важную оговорку: volatile даёт видимость и запрещает переупорядочивание вокруг себя, но не делает операцию атомарной — поэтому counter++ он не спасает, там по-прежнему три действия. Нормальный кейс — флаг остановки потока, while (!stopped). И happens-before мидл тоже назовёт: запись в volatile happens-before последующего чтения той же переменной и протаскивает за собой все записи, сделанные потоком до неё. Тут честно стоит сказать — в банковской базе happens-before помечен как Middle+, то есть это верх мидла, а не отдельная сеньорская планка.

🔴 Сеньор уходит в безопасную публикацию целиком, и вот это уже его территория. Почему double-checked locking до Java 5 был сломан: без гарантий модели памяти другой поток мог увидеть наполовину сконструированный объект, и чинится это volatile на поле синглтона. Почему immutable-объект с final-полями можно отдавать между потоками вообще без synchronized — JMM отдельно гарантирует видимость полностью построенного объекта через final. И обратная сторона: где volatile вешают зря — если доступ и так уже под одним замком, он не добавляет ничего, кроме шума. Сеньор отвечает не на «что такое happens-before», а на «как безопасно опубликовать состояние между потоками».


7. Индексы в базе

Тот самый вопрос с картинки в начале. Его удобно показывать именно лесенкой, потому что в одной и той же конторе его реально задают тремя ступенями.

🟢 Джун: индекс ускоряет поиск, как оглавление в книге — по индексированному полю WHERE отрабатывает быстрее, чем перебор всей таблицы. В ТБанке джунам так и формулируют: что такое индекс и почему нельзя навесить его на каждое поле.

🟡 Мидл: чаще всего B-tree — равенство, диапазоны, сортировка; hash — только равенство; GIN/GiST — полнотекст, массивы, гео. На каждый столбец нельзя: индекс занимает место и замедляет запись, потому что его надо обновлять при каждом INSERT/UPDATE/DELETE. Покрывающий (INCLUDE) отвечает на запрос, не заходя в таблицу; частичный (WHERE) индексирует подмножество строк; у составного важен порядок колонок, работает левый префикс. Это ровно мидловские формулировки из тех же интервью.

🔴 Сеньор живёт там, где индекс не срабатывает и где его накатывают на проде. Не сработает не на SARGable предикате — функция над колонкой, LIKE '%x%' с процентом в начале, неявный каст типов — и при низкой селективности: если запрос вернёт большую долю таблицы, планировщик сознательно уйдёт в seq scan, потому что так дешевле, и сеньор это читает по EXPLAIN (ANALYZE, BUFFERS). А на терабайтнике обычный CREATE INDEX лочит запись и встаёт колом, поэтому только CREATE INDEX CONCURRENTLY: дольше, в два прохода, при сбое оставляет INVALID-индекс на пересоздание, и внутри транзакции его не запустить. Эта верхняя ступень в базе и помечена как Middle+: «таблица на несколько терабайт — как накатить индекс, не убив прод».

Три ступени, одна компания. Собственно, с этого наблюдения вся статья и началась.


Почему планировщик выбирает seq scan

Почему планировщик выбирает seq scan

Слева индекс работает, справа — простаивает. Сеньор знает, почему планировщик выбрал seq scan.


8. @Transactional, который держит соединение

Мой любимый, и в банках его обожают. Формулировка обычно такая: повесили @Transactional на метод, а он внутри ходит синхронным REST-вызовом в соседний сервис. Что не так?

🟢 Джун ответит про основу и не ошибётся: @Transactional открывает транзакцию, при исключении откатывает, нужен, чтобы несколько операций с базой были атомарны — всё или ничего. ACID.

🟡 Мидл знает подводные камни механики, и это именно мидловский слой. По умолчанию откат только на RuntimeException и Error, на checked-исключение транзакция не откатится — нужен rollbackFor, и на этом регулярно горят. И про прокси: @Transactional работает через AOP-прокси, поэтому вызов метода изнутри того же бина (self-invocation) идёт мимо прокси, и транзакция не стартует; по той же причине private- и final-методы не перехватываются. Сюда же propagation и уровни изоляции, если попросят.

🔴 Сеньор видит в вопросе беду подороже и обычно рассказывает её как историю с прода. Синхронный HTTP держит транзакцию открытой ровно столько, сколько длится сетевой таймаут, а вместе с ней удерживает соединение из пула и блокировки на строках. Под нагрузкой пул вычерпывается, и ложится не один метод, а сервис целиком, каскадом — разгребать такое в три ночи незабываемо. Поэтому сеть внутри транзакции это антипаттерн: транзакция должна быть короткой и только про базу. Вызов выносят наружу, а согласованность с внешним миром делают через Outbox или Saga, иначе ловишь классику «сообщение в Kafka ушло, а транзакция откатилась». И ещё: долгая транзакция в PostgreSQL из-за MVCC удерживает старые версии строк и мешает VACUUM, таблицы пухнут. Сеньор тут про границы, ресурсы и согласованность под нагрузкой, а не про то, как оно откатывается.

Это фирменный вопрос ТБанка, в нескольких расшифровках почти слово в слово.

Сеньорская ловушка: сеть внутри @Transactional

Сеньорская ловушка: сеть внутри @Transactional

Транзакция держит соединение всё время сетевого таймаута — под нагрузкой пул вычерпывается, и ложится весь сервис.


Та же восьмёрка одним экраном

Если хочется просто пробежать перед собесом — вот всё, что выше, в одной таблице. Граница «мидл/сеньор» специально сдвинута к реальности: внутренности это мидл, прод и трейд-оффы это сеньор.

#

Вопрос

🟢 Джун

🟡 Мидл

🔴 Сеньор

1

equals / hashCode

равенство по значению, переопредели оба, равные → равный хэш

только equals → разные бакеты, get() не найдёт; не на мутабельных полях

стратегия для JPA-сущностей; getClass ломается на Hibernate-прокси → instanceof

2

HashMap внутри

пары, O(1) в среднем, массив

бакеты, load factor/resize, treeify ≥8, не потокобезопасен

выбор под нагрузку/память, цена resize в hot path, когда CHM или иная структура

3

String immutable

нельзя менять, пул, литерал = один объект

интернирование, new/intern, склейка vs мусор, кэш hashCode

TOCTOU-безопасность, грабли intern() на масштабе, Compact Strings (грань — опыт)

4

Optional

обёртка вместо null

orElse жадный / orElseGet ленивый, of/ofNullable, не get()

только возвращаемый тип: не поле, не Serializable, не Optional<List>

5

counter++

race condition, synchronized

три операции, AtomicInteger на CAS

LongAdder под контеншеном; а нужен ли общий счётчик вообще

6

volatile

видеть актуальное значение

видимость без атомарности; happens-before (это Middle+)

safe publication, final-поля, почему DCL нужен volatile, когда volatile не нужен

7

Индексы

ускоряют поиск

типы, покрывающий/частичный, цена записи

SARGability, селективность и seq scan, CONCURRENTLY, чтение EXPLAIN

8

@Transactional

откат при ошибке, ACID

rollbackFor, прокси, self-invocation, propagation

держит соединение → вычерпывает пул → каскад; Outbox/Saga; MVCC и VACUUM


Никакой магии в «определении грейда» нет. Берёте любой вопрос и говорите вслух, пока есть что сказать.

Закончились на зелёном — это честный джун, и на старте абсолютно нормально; дальше растёт не список тем, а глубина по каждой. Дошли до жёлтого, можете объяснить, как оно устроено внутри и где ломается, — это мидл, и, к слову, большинство офферов закрывается именно тут. А красное — это уже не «знаю ещё больше внутренностей». Это когда вы сами, без наводящих, выходите на прод: что будет под нагрузкой, чем платим, когда это решение вообще не надо применять. Вот это и пишут в фидбэке словом «Senior».

Грейд — это не сколько фактов вы помните. Это где вы перестаёте говорить про код и начинаете про его последствия.

Грейд — это глубина ответа, а не список тем

Грейд — это глубина ответа, а не список тем

Та самая мысль одной картинкой: внутренности — это Middle, прод и трейд-оффы — Senior.


Это уже третий разбор про реальные банковские собесы. Senior System Design я по-прежнему должен, помню, он будет — просто это большой кусок, и наспех не хочется.

А пока проверим формат на вас. Возьмите в комментариях любой вопрос из восьми и допишите красную строку своими словами — как бы вы закрыли его на сеньорском уровне, через прод и трейд-оффы, а не через «ещё внутренности». Самое толковое утащу в отдельный разбор в канал, с указанием авторства. Не согласны со мной, где проходит граница мидла и сеньора, — тем интереснее, спорьте по делу, я тут не истина в последней инстанции.

И отдельное спасибо тем, кто честно признается, на какой строчке встал. Сказать себе «я пока на жёлтой» — это уже полпути до красной.


Пишу про разбор java-собесов и реальные вопросы, которые задают, без курсов и рекламы — канал @Java_Jub.