java-interview

Собес в Лигу Цифровой Экономики · Java Middle

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

Темы: Java 11+ · Spring · Hibernate · PostgreSQL · JUnit · Docker · Jenkins

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


1. Про Лигу и формат собеса

Лига Цифровой Экономики — крупный российский IT-интегратор (6 000+ человек, больше 1 000 проектов в год). Клиенты: Сбер, ВТБ, Альфа-Банк, Ростелеком, МТС, Роснефть, МВД, министерства. Для Java Middle это значит: проекты чаще всего банковские или государственные, с жёсткими требованиями к качеству и тестированию.

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

Этап Длительность Что проверяют
Скрининг HR 20–30 мин Мотивация, ЗП-ожидания, согласие на ТК РФ
Тех-интервью 60–90 мин Java Core + live-coding + SQL
Интервью с 30–60 мин Проект, команда, матч по софтам

руководителем

Проверка СБ до недели Стандартная для госпроектов
Оффер По ТК РФ, ДМС, стоматология

Как проходит техническая секция

ФИШКА. Ключевая особенность Лиги По отзывам кандидатов на DreamJob: «Лайфкодинг, понимание SQL. Спрашивают твоё умение мыслить, а не теоретическую подготовку». Готовься не пересказывать учебник, а писать код и объяснять, почему именно так.

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

На апрель 2026 года на Хабр Карьере актуальна вакансия Java Middle в Лиге — в команду антифрод-решения ведущего банка. Стек оттуда — наш основной ориентир.

Обязательный минимум

Будет плюсом

ВНИМАНИЕ · Что это значит для подготовки Стек приземлённый — никаких Virtual Threads, ZGC, GraalVM и прочего хайпа. Ждут крепкое владение Java 11 + Spring + Hibernate + SQL + тестами. Всё остальное — бонус.

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

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

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

4. Коллекции

HashMap — чемпион по частоте вопросов. Готовься рассказывать «как устроено».

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

Для Middle ждут уверенное понимание synchronized, volatile, JMM и пулов потоков.

6. Spring и Spring Boot

В вакансии указан Spring 5–6 и Spring Boot 2–3. Блок обязательный, готовься основательно.

7. Hibernate и Spring Data JPA

В вакансии Hibernate и Spring Data прописаны явно. Ждут уверенную базу.

8. SQL и PostgreSQL

В отзывах кандидатов Лиги SQL упоминают отдельно — спрашивают понимание, не теорию. Будь готов писать запросы живьём.

9. Тесты: JUnit, Mockito, TDD

В Лиге тесты — часть инженерной культуры: вакансия прямо требует TDD, JUnit 5, Mockito, Hamcrest, AssertJ.

10. Docker, Jenkins, Linux

Docker

Jenkins и CI/CD

Linux — базовый минимум

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

По отзывам кандидатов — в Лиге на Java Middle любят живое кодирование с рассуждением. Задачи прикладные, без LeetCode Hard.

Задача 1. Найти дубликаты в списке

Формулировка: дан List. Вернуть Set чисел, которые встречаются более одного раза.

public Set<Integer> findDuplicates(List<Integer> list) {
    Set<Integer> seen = new HashSet<>();
    Set<Integer> duplicates = new HashSet<>();
    for (Integer n : list) {
        if (!seen.add(n)) {
            duplicates.add(n);
        }
    }
    return duplicates;
}

Или через Stream API:

public Set<Integer> findDuplicates(List<Integer> list) {
    return list.stream()
        .collect(Collectors.groupingBy(n -> n, Collectors.counting()))
        .entrySet().stream()
        .filter(e -> e.getValue() > 1)
        .map(Map.Entry::getKey)
        .collect(Collectors.toSet());
}

Что спросят: сложность (первый вариант O(n), второй — тоже O(n), но с бóльшей константой), можно ли без HashSet, что будет если в списке null.

Задача 2. Группировать сотрудников по отделам

Формулировка: дан List, у каждого есть имя и отдел. Вернуть Map<String, List> — отдел → список сотрудников.

public Map<String, List<Employee>> groupByDepartment(List<Employee> employees) {
    return employees.stream()
        .collect(Collectors.groupingBy(Employee::getDepartment));
}

Частое продолжение: «А теперь получить Map<String, Long> — отдел → количество сотрудников». Ответ — Collectors.counting() как downstream: Map<String, Long> counts = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.counting()

));

Задача 3. SQL-запрос вживую

Такого типа задачу в Лиге дают почти всегда. Умеешь ли ты писать JOIN, GROUP BY, HAVING и объяснять план. Типовая формулировка: есть таблицы employees(id, name, department_id, salary) и departments(id, name). Выведи названия отделов, где средняя зарплата выше 100 000, отсортируй по убыванию средней.

SELECT d.name, AVG(e.salary) AS avg_salary
FROM employees e
JOIN departments d ON d.id = e.department_id
GROUP BY d.name
HAVING AVG(e.salary) > 100000
ORDER BY avg_salary DESC;

Почти наверняка продолжат спрашивать

Задача 4. REST-контроллер на Spring Boot

Формулировка: «Напиши контроллер, который принимает POST /api/users с телом JSON, валидирует его и сохраняет через сервис». Типичное задание вживую.

@RestController
@RequestMapping("/api/users")
public class UserController {

        private final UserService userService;

        public UserController(UserService userService) {
            this.userService = userService;
        }

        @PostMapping
        @ResponseStatus(HttpStatus.CREATED)
        public UserDto create(@RequestBody @Valid CreateUserRequest request) {
            return userService.create(request);
        }

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

public record CreateUserRequest(
    @NotBlank String name,
    @Email String email,
    @Min(18) int age
) {}

На что обратят внимание

Задача 5. Написать unit-тест к сервису

Формулировка: «Вот сервис UserService, зависит от UserRepository и EmailSender. Напиши тест для метода register(email, name), который создаёт пользователя, сохраняет и отправляет приветственное письмо». С учётом TDD в Лиге задают часто.

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

        @Mock
        private UserRepository userRepository;

        @Mock
        private EmailSender emailSender;

        @InjectMocks
        private UserService userService;

        @Test
        void shouldRegisterUserAndSendEmail() {
            // given
            String email = "alice@example.com";
            String name = "Alice";
            User saved = new User(1L, name, email);
            when(userRepository.save(any(User.class))).thenReturn(saved);

               // when
               User result = userService.register(email, name);

               // then
               assertThat(result.getId()).isEqualTo(1L);
               assertThat(result.getEmail()).isEqualTo(email);

               ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
               verify(userRepository).save(captor.capture());
               assertThat(captor.getValue().getName()).isEqualTo(name);

               verify(emailSender).sendWelcome(email);
        }
}

Что важно

Задача 6. N+1 — найти и починить

Формулировка: «Вот код репозитория и сервиса. Приложение тормозит на выводе списка заказов с их товарами. В чём проблема, как исправить?»

@Entity
public class Order {
    @Id
    private Long id;

        @OneToMany(mappedBy = "order")    // LAZY by default
        private List<OrderItem> items;
}

// В сервисе:
List<Order> orders = orderRepository.findAll();
for (Order o : orders) {
    System.out.println(o.getItems().size()); // +1 запрос на каждый Order
}

Что случилось 1 запрос на findAll() + N запросов на каждую коллекцию items — та самая N+1. При 1000 заказов — 1001 SQL-запрос.

Как чинить

ЛОВУШКА · Ловушка «Просто поставить EAGER» — неправильный ответ. EAGER грузит коллекцию ВСЕГДА, даже когда она не нужна. Это медленнее и съедает память. Правильно — LAZY по умолчанию + FETCH там, где надо.

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

Формулировка: «Напиши простой кэш Map<String, String>, в который пишут и читают из разных потоков. Чтобы работало правильно».

Минимальный правильный вариант

public class SimpleCache {
    private final Map<String, String> cache = new ConcurrentHashMap<>();

        public String get(String key, Function<String, String> loader) {
            return cache.computeIfAbsent(key, loader);
        }
}

Что спросят

Задача 8. Анаграммы

Классика для разминки. Формулировка: «Две строки — анаграммы, если состоят из одних и тех же букв в разном порядке. Проверь».

public boolean isAnagram(String a, String b) {
    if (a == null || b == null || a.length() != b.length()) return false;
    char[] aChars = a.toLowerCase().toCharArray();
    char[] bChars = b.toLowerCase().toCharArray();
    Arrays.sort(aChars);
    Arrays.sort(bChars);
    return Arrays.equals(aChars, bChars);
}

Сложность: O(n log n) из-за sort. Можно ли быстрее — да, за O(n) через массив счётчиков int[26] (для ASCII) или HashMap<Character, Integer> для Unicode.

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

За 2–3 недели

  1. Прорешать 20–30 задач на LeetCode (Easy + Medium) на массивы, строки, хэш-таблицы, Stream API. 2. Поднять pet-проект на Spring Boot 3 + PostgreSQL + Testcontainers. Если есть — отрефакторить. 3. Прокачать Hibernate: разобраться с N+1, состояниями сущности, JOIN FETCH, @EntityGraph. 4. Повторить SQL: JOIN, GROUP BY, HAVING, оконные функции, EXPLAIN ANALYZE. 5. Написать 5–10 unit-тестов с Mockito + AssertJ. Попробовать подход TDD.

За неделю

  1. 2–3 мок-интервью: проси друзей или используй pramp.com / interviewing.io. 7. Прорешать вопросы из этого гайда вслух — проговорить реально важно. 8. Подготовить 2–3 истории по схеме: проблема → что сделал → результат (с цифрами). 9. Освежить Docker: написать Dockerfile и docker-compose для pet-проекта.

В день собеса

ВНИМАНИЕ · Про банковские проекты Большинство Java-вакансий в Лиге — в банки (по актуальной вакансии — антифрод крупного банка). Будь готов, что проверку СБ и оформление по ТК РФ делают серьёзно. Удалёнка возможна, но обычно из РФ.

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

Блок Готов, если можешь…
Java Core Объяснить контракт equals/hashCode на примере и показать, как его

нарушение ломает HashSet

Коллекции Рассказать, как устроен HashMap в Java 8+, и почему плохо держать mutable-объект ключом

Многопоточность Написать потокобезопасный singleton и объяснить роль volatile в DCL
JMM Объяснить happens-before на примере volatile и synchronized
Spring Рассказать, почему @Transactional не работает при self-invocation
Hibernate Найти N+1 в коде и предложить 2+ способа починить
SQL Написать запрос с JOIN + GROUP BY + HAVING и обосновать индекс
Тесты Написать тест с Mockito + ArgumentCaptor + AssertJ
Docker Написать Dockerfile с multi-stage build для Spring Boot
Live-coding За 15 минут написать чистое решение задачи типа ‘group by

department’

━━━━━━━━━━━━━━━━━━━━━━━━


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

// git push origin offer


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

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