офлайн
офлайн
ГлавнаяCode Review Java и Spring.md
---
tags: [java, spring, interview]
created: 2026-11-06
updated: 
---

Code Review Java и Spring

Javajavaspringinterview4 мин
Содержание

Топ-паттернов ошибок на Code Review (Java/Spring)

Spring Framework

  • Proxy Bypass (Self-invocation): Вызов метода с @Transactional, @Async или @Cacheable из другого метода того же класса.
    • Суть: Spring использует прокси. Внутренний вызов игнорирует прокси, аннотация не срабатывает.
    • Решение: Выносить метод в другой бин или использовать ApplicationContext (хуже).
  • Stateful Singleton (Состояние гонки в бинах): Использование мутабельных полей (коллекций, счетчиков) в @Service или @Component.
    • Суть: Spring-бины — синглтоны. При конкурентных запросах данные перемешаются.
    • Решение: Хранить состояние в БД/кэше, либо использовать ThreadLocal / потокобезопасные коллекции (если это оправдано).
  • Transaction Starvation (I/O внутри транзакции): Сетевые вызовы (HTTP/gRPC) или тяжелая работа с файлами внутри @Transactional.
    • Суть: Пул соединений с БД (HikariCP) блокируется на время ответа внешней системы. При нагрузке пул исчерпается, приложение “ляжет”.
  • Implicit Transaction Rollback (Откат только по RuntimeException): Выброс Checked Exception (например, IOException) внутри @Transactional.
    • Суть: По умолчанию Spring не откатывает транзакции при Checked исключениях.
    • Решение: Использовать @Transactional(rollbackFor = Exception.class).

Базы данных, JPA и Hibernate

  • N+1 Query Problem: Ленивая загрузка связанных сущностей (@OneToMany) внутри цикла.
    • Суть: Вместо 1 запроса выполняется 1+N.
    • Решение: Использовать JOIN FETCH, @EntityGraph или DTO-проекции.
  • Lombok-ловушки в JPA (@Data, @ToString, @EqualsAndHashCode): Использование этих аннотаций над @Entity.
    • Суть: Вызов toString() или equals() дергает ленивые связи, вызывая LazyInitializationException или StackOverflowError (при двунаправленных связях).
  • Misunderstanding Dirty Checking: Ручной вызов save() для уже прикрепленной (attached) к Hibernate-сессии сущности, или ожидание сохранения без @Transactional.
  • Missing Modification Context: Использование кастомных @Query("UPDATE/DELETE...") без @Modifying.
  • Open Session In View (OSIV) Anti-pattern: Включенный по умолчанию в Spring Boot OSIV.
    • Суть: Транзакция БД закрывается, но сессия БД держится открытой до конца рендеринга HTTP-ответа. Ведет к истощению пула коннектов.

Многопоточность и Concurrency

  • Non-Atomic “Check-then-Act”: Проверка состояния и последующее изменение (например, if (!map.containsKey()) map.put()) без синхронизации.
    • Суть: Между проверкой и действием другой поток может изменить состояние.
    • Решение: Использовать putIfAbsent, computeIfAbsent или блокировки.
  • False Atomicity (Иллюзия атомарности volatile): Использование volatile для операций инкремента (counter++).
    • Суть: volatile гарантирует только видимость (visibility), но не атомарность. Инкремент — это 3 операции.
    • Решение: AtomicInteger или synchronized.
  • Thread-Unsafe Standard Classes: Использование SimpleDateFormat или MessageDigest как статических констант.
    • Суть: Они не потокобезопасны.
    • Решение: Использовать DateTimeFormatter (java.time) или ThreadLocal.
  • Lost Async Exceptions: Запуск задач через ExecutorService.submit() без вызова .get() у Future.
    • Суть: Исключения внутри потока “проглатываются” и не попадают в лог.

Core Java, Collections и Stream API

  • Side-Effects in Streams: Мутация внешней коллекции внутри stream().forEach() или map().
    • Суть: Нарушает функциональную парадигму, при .parallelStream() ведет к потере данных или ConcurrentModificationException.
    • Решение: Использовать .collect().
  • Optional Misuse: Вызов .get() без .isPresent(), использование Optional в полях класса или аргументах методов.
    • Суть: Optional создан только для возвращаемых значений методов, чтобы избежать NPE.
  • Suboptimal Lookups (O(N^2) Complexity): Использование List.contains() внутри цикла или фильтра стрима.
    • Суть: Поиск по списку работает за O(N).
    • Решение: Конвертировать список для поиска в HashSet (O(1)) до начала цикла/стрима.
  • Unclosed Resources: Работа с потоками ввода-вывода (I/O) или JDBC без try-with-resources.
  • Floating Point Money (Деньги в double/float): Использование типов с плавающей точкой для финансовых расчетов.
    • Суть: Стандарт IEEE 754 не может точно представить некоторые дроби (0.1 + 0.2 != 0.3).
    • Решение: Только BigDecimal (с конструктором от String) или хранение в копейках/центах (long).
  • Reference vs Value Equality: Сравнение объектов (String, Integer) через == вместо .equals().
    • Суть: Сравниваются ссылки в памяти. Из-за пула строк и кэша Integer (-128..127) баг может плавать.

5. Архитектура, Логирование и Безопасность

  • Log and Throw Anti-pattern: Логирование ошибки и немедленный проброс её же выше по стеку.
    • Суть: Дублирование одного и того же стектрейса на всех слоях приложения.
    • Решение: Либо логируй и обрабатывай, либо пробрасывай дальше.
  • Swallowed Exceptions: Пустой блок catch или логирование только e.getMessage() без передачи самого объекта исключения.
    • Суть: Потеря стектрейса, невозможность расследовать инцидент.
  • Yoda Conditions (NPE Hazard): Вызов .equals() у переменной, которая может быть null (status.equals("ACTIVE")).
    • Решение: Константа всегда слева: "ACTIVE".equals(status) или Objects.equals().
  • Leaking Entities (Сущности БД в API): Возврат JPA @Entity напрямую из REST-контроллера.
  • Суть: Жесткая связность БД и контракта API, риск утечки чувствительных данных (пароли, хеши).
  • Решение: Маппинг Entity в DTO (Record) на сервисном слое.
  • Fat Controllers: Наличие бизнес-логики (if/else, расчеты) прямо в методах @RestController.
    • Суть: Контроллер должен только валидировать HTTP-запрос, вызывать сервис и отдавать HTTP-ответ. Логика должна быть в @Service.
main48 заметок661 слов4 мин чтения