java-interview

Собес в Яндекс Путешествия (Яндекс Вертикали) · Java Middle

Вопросы, задачи и подготовка к live-coding и техническому интервью.

Темы: Java · Kotlin · Spring Boot · PostgreSQL · YDB · gRPC · Logbroker · Kubernetes

← Ко всем гайдам · Канал JavaJub в Telegram


1. Яндекс Путешествия и формат собеса

Яндекс Путешествия — часть бизнес-юнита Яндекс Вертикали (вместе с Авто.ру, Недвижимостью, Арендой). Это единственное крупное JVM-направление Яндекса наряду с Маркетом — можно прийти с обычным Java-бэкграундом, не переучиваясь на C++, Go или Scala. Команда ~40+ бэкенд-разработчиков. Продукты: отели, авиа, ж/д, автобусы, B2B-командировки, экстранет для отельеров, биллинговая платформа. Нагрузка — десятки тысяч RPS, миллионы DAU.

Как устроен процесс

Яндекс нанимает через общий поток «бэкенд в Путешествия». Уровень (Middle / Middle+ / Senior) определяется по итогам секций, а не указывается в вакансии. Секции оцениваются независимо — интервьюеры не обсуждают результаты до финальной калибровки.

Этап Формат Длительность
HR-скрининг Zoom, мотивация, ЗП 30–60 мин
Техническое предварительное Yandex.Code (без компиляции) 1 час
Advanced Code (с 2025) IDE кандидата + автотесты + 1 час

интернет

Алгоритмическая секция Yandex.Code, 2–3 задачи 1 час
Java Core + многопоточность Yandex.Code, теория + код 1–1.5 часа
System Design Miro + Zoom 1 час (опц. для Middle)
Секция «про опыт» (STAR) Разбор проектов 1 час
Финалы с командами 2–5 команд по 1 часу 2–5 часов

ФИШКА. Ключевая особенность Можно провалить 1–2 секции и всё равно получить оффер — секции оцениваются независимо. В сомнительных случаях просто назначают дополнительную секцию. После отказа можно перезайти через 6–12 месяцев.

ВНИМАНИЕ · Про алгоритмы Алгоритмическая секция — главный фильтр. Уровень сравним с Google. НО: Яндекс официально заявляет, что НЕ дают динамическое программирование, Дейкстру, KMP. Фокус — хэш-таблицы, два указателя, sliding window, BFS/DFS.

2. Стек по вакансии

Стек определён по вакансии «Разработчик на Java в Путешествия» (yandex.ru/jobs) и карточке на career.habr.com. Путешествия отличаются от остальных Вертикалей: Авто.ру пишет на Scala + ZIO, а Путешествия — на Java + Kotlin + Spring.

Основной стек

Что важно знать

СОВЕТ. Для Java-разработчика Путешествия — наиболее «дружественное» подразделение Яндекса для классического Java-разработчика: привычный стек Spring/Hibernate/PostgreSQL + Kotlin. Внутренние технологии (YDB, Logbroker, Arcadia) изучаются уже на месте.

3. Java Core — что точно спросят

По отзывам кандидатов (Medium, Habr 968968, Habr 854956): equals/hashCode + HashMap — абсолютные чемпионы. Далее — Stream API, generics, String Pool, ссылочные типы.

Базовые вопросы

Задачи «Что выведет?»

Тест 1. Integer cache

Integer i1 = 127, i2 = 127;
System.out.println(i1 == i2); // ?

Integer i3 = 128, i4 = 128;
System.out.println(i3 == i4); // ?

Ответ: true, false. IntegerCache: -128..127. Для 127 — один объект, ссылки совпадают. Для 128 — два разных. Мораль: для объектов — equals(), никогда ==.

Тест 2. Stream — ленивость List.of(1,2,3,4,5).stream()

.map(x -> { System.out.print(x+" "); return x; })
.filter(x -> x > 2)
.map(x -> { System.out.print(x+" "); return x; })
.toList();

Ответ: 1 2 3 3 4 4 5 5. Стрим обрабатывает вертикально: каждый элемент проходит всю цепочку. 1 и 2 не проходят filter → печатаются раз. 3,4,5 проходят → дважды.

Тест 3. Передача по значению

Integer i = Integer.valueOf(1);
inc(i);
System.out.println(i); // ?

static void inc(Integer i) { i++; }

Ответ: 1. Java передаёт ссылки по значению. i++ создаёт новый Integer(2) и присваивает локальной переменной. Оригинал не меняется.

СОВЕТ. Лайфхак На вопрос про equals/hashCode приведи практический пример: «положить объект в HashSet, изменить поле в hashCode — объект потеряется, contains() вернёт false». Это показывает понимание, а не заученность.

4. Коллекции

HashMap — чемпион. По опыту кандидатов в Яндекс: «обсасывают мапу со всех сторон — устройство, коллизии, treeify, resize, ключи-массивы, что будет если положить и не найти».

5. Многопоточность и JMM

В Яндексе многопоточность спрашивают глубоко — volatile vs synchronized давали на каждом собесе. JMM, happens-before, CAS, пулы потоков — обязательно.

ЛОВУШКА · volatile counter++ volatile long counter; counter++ — НЕВЕРНО. Это три операции (read-increment-write), volatile не обеспечивает атомарность. Три корректных варианта: synchronized, AtomicLong.incrementAndGet(), LongAdder.increment().

6. Spring и Spring Boot

Spring — основной фреймворк Путешествий. Спрашивают глубоко: прокси, жизненный цикл бинов, автоконфигурация, AOP.

7. Hibernate и JPA

ЛОВУШКА · EAGER = решение N+1? Нет. EAGER грузит коллекцию ВСЕГДА, даже когда она не нужна — медленнее и съедает память. Правильно: LAZY по умолчанию + FETCH/EntityGraph там, где нужны данные.

8. SQL и PostgreSQL

SQL спрашивают отдельной задачей — пишешь запросы вживую. Оконные функции, EXPLAIN ANALYZE, уровни изоляции — обязательно для Яндекса.

SQL-задачи из собесов Яндекса

Вторая по величине зарплата (3 способа) – Способ 1: вложенный MAX

SELECT MAX(salary) FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);

-- Способ 2: DISTINCT + OFFSET
SELECT DISTINCT salary FROM employees
ORDER BY salary DESC LIMIT 1 OFFSET 1;

-- Способ 3: DENSE_RANK
SELECT salary FROM (
  SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rk
  FROM employees) t WHERE rk = 2;

Топ-5 артикулов в каждом регионе

SELECT * FROM (
  SELECT region, article, sales,
    ROW_NUMBER() OVER (PARTITION BY region ORDER BY sales DESC) AS rn
  FROM sales_data
) t WHERE rn <= 5;

9. Алгоритмы — главный фильтр

Алгоритмическая секция — самая обсуждаемая часть. 2–3 задачи за 1 час, решения в 10–30 строк. Код пишется в Yandex.Code — без компиляции, без автокомплита. Ключевое: умение «прогнать» код в голове.

Что НЕ спрашивают (официально)

Что спрашивают (по отзывам)

Реальные задачи из собесов Яндекса

Задача 1. Сжатие в диапазоны Дан массив [1,4,5,2,3,9,8,11,0]. Вернуть строку “0-5,8-9,11”.

public String compressRanges(int[] arr) {
    Arrays.sort(arr);
    StringBuilder sb = new StringBuilder();
    int i = 0;
    while (i < arr.length) {
        int start = arr[i];
        while (i + 1 < arr.length && arr[i+1] == arr[i] + 1) i++;
        if (arr[i] == start) sb.append(start);
        else sb.append(start).append('-').append(arr[i]);
        sb.append(',');
        i++;
    }
    sb.setLength(sb.length() - 1);
    return sb.toString();
}

O(n log n) из-за сортировки. Два указателя для расширения диапазона.

Задача 2. Run-Length Encoding

public String rle(String s) {
    StringBuilder sb = new StringBuilder();
    int i = 0;
    while (i < s.length()) {
        char c = s.charAt(i);
        int count = 0;
        while (i < s.length() && s.charAt(i) == c) {
            count++; i++;
        }
        if (count > 1) sb.append(count);
        sb.append(c);
    }
    return sb.toString();
}

aaaffccccd → 3a2f4cd. O(n) времени и памяти.

Задача 3. Merge Intervals

public int[][] merge(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
    List<int[]> result = new ArrayList<>();
    int[] current = intervals[0];
    for (int i = 1; i < intervals.length; i++) {
        if (intervals[i][0] <= current[1]) {
            current[1] = Math.max(current[1], intervals[i][1]);
        } else {
            result.add(current);
            current = intervals[i];
        }
    }
    result.add(current);
    return result.toArray(new int[0][]);
}

O(n log n). Сортировка по началу + жадное слияние.

Задача 4. Детектор роботов (sliding window) Дан поток событий (userId, timestamp). Найти пользователей с >5000 событиями за любой час.

Map<Long, Deque<Long>> windows = new HashMap<>();

void processEvent(long userId, long timestamp) {
    windows.computeIfAbsent(userId, k -> new ArrayDeque<>());
    Deque<Long> deque = windows.get(userId);
    deque.addLast(timestamp);
    while (deque.peekFirst() < timestamp - 3600) {
        deque.pollFirst();
    }
    if (deque.size() > 5000) {
        markAsBot(userId);
    }
}

ФИШКА. Тренировочный контест Официальный контест Яндекса — contest.yandex.ru/contest/8458. 6 задач: камни, последовательные единицы, дубликаты, скобки, анаграммы, слияние k массивов. Прорешай его перед собесом.

10. System Design

Для Middle секция необязательна, но сильный результат поднимет грейд (Middle → Middle+). Для Senior — ключевая. Кандидат ведёт обсуждение, интервьюер задаёт наводящие вопросы.

Что оценивают

Реальные задачи из Яндекса

11. Docker, Kubernetes, CI/CD

Яндекс использует свои инструменты деплоя (Nanny / Yandex Deploy), но принципы контейнеризации и CI/CD спрашивают. Docker и K8s — must-have знание.

12. Практические задачи (live-coding)

Помимо алгоритмов, на собесе в Яндекс могут попросить написать REST-контроллер, unit-тест, или решить задачу на Stream API. С 2025 года — секция Advanced Code: IDE + автотесты + интернет.

Задача 1. Группировка Stream API

// Отдел → список сотрудников Map<String, List> byDept = employees.stream()

.collect(Collectors.groupingBy(Employee::getDepartment));

// Отдел → средняя зарплата Map<String, Double> avg = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment,

Collectors.averagingDouble(Employee::getSalary)));

Задача 2. Потокобезопасный LRU-кэш

public class LRUCache<K, V> {
    private final int capacity;
    private final Map<K, V> map;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new LinkedHashMap<>(capacity, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> e) {
                return size() > capacity;
            }
        };
    }

    public synchronized V get(K key) { return map.get(key); }
    public synchronized void put(K key, V value) { map.put(key, value); }
}

LinkedHashMap с accessOrder=true + removeEldestEntry. synchronized для потокобезопасности. Для высокой нагрузки — Caffeine.

Задача 3. REST-контроллер

@RestController
@RequestMapping("/api/bookings")
public class BookingController {

    private final BookingService bookingService;

    public BookingController(BookingService bookingService) {
        this.bookingService = bookingService;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public BookingDto create(@RequestBody @Valid CreateBookingRequest req) {
        return bookingService.create(req);
    }

    @GetMapping("/{id}")
    public BookingDto getById(@PathVariable Long id) {
        return bookingService.findById(id);
    }
}

Задача 4. Unit-тест Mockito + AssertJ

@ExtendWith(MockitoExtension.class)
class BookingServiceTest {
    @Mock BookingRepository repo;
    @Mock PaymentGateway gateway;
    @InjectMocks BookingService service;

    @Test
    void shouldCreateBookingAndCharge() {
        // given
        var req = new CreateBookingRequest("hotel-1", LocalDate.now());
        var saved = new Booking(1L, "hotel-1", Status.CONFIRMED);
        when(repo.save(any())).thenReturn(saved);
        // when
        var result = service.create(req);
        // then
        assertThat(result.getStatus()).isEqualTo(Status.CONFIRMED);
        verify(gateway).charge(any());
    }
}

Задача 5. Code Review — найди проблемы

public class UserCache {
    private static Map<Long, User> cache = new HashMap<>();

    public static User getUser(Long id) {
        if (cache.containsKey(id)) {
            return cache.get(id);
        }
        User user = loadFromDb(id);
        cache.put(id, user);
        return user;
    }
}

Проблемы: 1) HashMap не потокобезопасен → ConcurrentHashMap. 2) containsKey+get → computeIfAbsent. 3) Кэш бесконечный → memory leak. 4) static → тяжело тестировать. 5) null от loadFromDb.

13. План подготовки + чек-лист

За 3–4 недели

За неделю

В день собеса

ВНИМАНИЕ · Главная причина отказов Не незнание теории, а невнятное изложение решения и баги, которые кандидат не замечает при прогоне кода в голове. Тренируйтесь писать и проверять код без IDE!

Финальный чек-лист

Блок Готов, если можешь…
Java Core equals/hashCode на примере + Integer cache +

generics PECS

Коллекции HashMap в Java 8+: treeify, resize, mutable-ключ, byte[] как ключ

Многопоточность BlockingQueue через wait/notify + volatile vs synchronized + CAS

JMM happens-before на 5+ примерах, почему volatile counter++ некорректно

Spring Жизненный цикл бина наизусть + self-call + JDK vs CGLIB прокси

Hibernate N+1 → JOIN FETCH / @EntityGraph / DTO. JOOQ vs Hibernate — когда что

SQL Оконные функции + EXPLAIN ANALYZE + вторая зарплата 3 способами

Алгоритмы 3 задачи за 1 час в текстовом редакторе БЕЗ компиляции

System Design Short URL или Rate Limiter с расчётами RPS и выбором технологий

Live-coding LRU-кэш + REST-контроллер + code review за 15 минут каждое


Удачи на собесе!

// git push origin offer


Гайд из канала JavaJub — свежие разборы собесов выходят там первыми: @java_jub.

← Ко всем гайдам