Библиотека собеса по Java | вопросы с собеседований
6.48K subscribers
433 photos
11 videos
712 links
Вопросы с собеседований по Java и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: clc.to/3wECtA

Для обратной связи: @proglibrary_feeedback_bot
Download Telegram
✔️ Java-тест: бин-синглтон, который не синглтон

Работает у одного, но ломается у другого. В логах каша из чужих данных 👇

📦 Задание — code review


Команда добавила контекст текущего пользователя в сервис через поле. Локально — всё ок.
На проде с несколькими потоками — пользователи видят чужие данные.

@Service
public class ReportService {

private User currentUser;
private ReportFilter activeFilter;

private final ReportRepository reportRepository;

public ReportService(ReportRepository reportRepository) {
this.reportRepository = reportRepository;
}

public void initContext(User user, ReportFilter filter) {
this.currentUser = user;
this.activeFilter = filter;
}

public List<Report> getReports() {
if (currentUser == null) {
throw new IllegalStateException("Context not initialized");
}

return reportRepository.findByUserAndFilter(
currentUser.getId(),
activeFilter
);
}

public ReportSummary getSummary() {
List<Report> reports = getReports();
return ReportSummary.calculate(reports, currentUser);
}
}


▪️ Объясни

— Какой скоуп у бина по умолчанию в Spring и почему это делает поля-состояния опасными.
— Почему synchronized над методами не является правильным решением здесь.
— Как переписать код, чтобы работало.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥83👍2👏1
✔️ Java-тест: кэш, который врёт

Метод возвращает устаревшие данные. Иногда и только на нескольких потоках. Воспроизвести локально — нереально 👇

📦 Задание — code review

Команда добавила простой in-memory кэш для тяжёлых вычислений. На одном потоке работает идеально. На проде с нагрузкой — иногда возвращает старый результат или null.

@Component
public class PricingCache {

private final Map<String, BigDecimal> cache = new HashMap<>();
private final PricingEngine pricingEngine;

public PricingCache(PricingEngine pricingEngine) {
this.pricingEngine = pricingEngine;
}

public BigDecimal getPrice(String productId) {
if (cache.containsKey(productId)) {
return cache.get(productId);
}
BigDecimal price = pricingEngine.calculate(productId);
cache.put(productId, price);
return price;
}

public void invalidate(String productId) {
cache.remove(productId);
}

public void invalidateAll() {
cache.clear();
}
}


▪️ Объясни

— В чём проблема в коде
— Как переписать getPrice верно

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍31🤔1
✔️ Java-тест: транзакция, которая не откатывается

@Transactional стоит, исключение летит. Данные в БД остаются. Почему?

📦 Задание — code review

Команда добавила транзакцию на метод сохранения заказа. При ошибке валидации данные всё равно коммитятся в базу. @Transactional на месте, но не работает.

public class CheckedBusinessException extends Exception {
public CheckedBusinessException(String message) {
super(message);
}
}

@Service
public class OrderService {

private final OrderRepository orderRepository;
private final InventoryService inventoryService;

@Transactional
public void placeOrder(Order order) throws CheckedBusinessException {
orderRepository.save(order);
inventoryService.reserveStock(order);
}
}

@Service
public class InventoryService {

public void reserveStock(Order order) throws CheckedBusinessException {
if (order.getQuantity() > availableStock) {
throw new CheckedBusinessException("Not enough stock");
}
}
}


▪️ Почему @Transactional не откатывает изменения при CheckedBusinessException?
▪️ Как добиться rollback в этом коде

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥93👍3
✔️ Java-тест: объект в HashSet есть, но contains() возвращает false

Добавили объект в Set. Он там. Но найти его невозможно. Утечка памяти в проде. Почему?

📦 Задание — code review

Команда хранит активные сессии в HashSet. После смены роли пользователя сессия «пропадает» из множества — contains() возвращает false, remove() не удаляет. Set растёт, память течёт.
public class UserSession {
private Long userId;
private String role;

public UserSession(Long userId, String role) {
this.userId = userId;
this.role = role;
}

// getters, setters

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserSession that = (UserSession) o;
return Objects.equals(userId, that.userId)
&& Objects.equals(role, that.role);
}

@Override
public int hashCode() {
return Objects.hash(userId, role);
}
}

@Service
public class SessionManager {

private final Set<UserSession> activeSessions = new HashSet<>();

public void addSession(UserSession session) {
activeSessions.add(session);
}

public void promoteToAdmin(Long userId) {
activeSessions.stream()
.filter(s -> s.getUserId().equals(userId))
.findFirst()
.ifPresent(s -> s.setRole("ADMIN"));
}

public boolean isActive(UserSession session) {
return activeSessions.contains(session);
}

public void removeSession(UserSession session) {
activeSessions.remove(session);
}
}


// Сценарий бага:
sessionManager.addSession(new UserSession(1L, "USER")); // ОК
sessionManager.promoteToAdmin(1L); // меняем роль
sessionManager.isActive(new UserSession(1L, "ADMIN")); // false ?!
// объект внутри Set есть, но достать его нельзя


▪️ Почему после promoteToAdmin() сессия становится невидимой для contains() и remove()?
▪️ Как исправить, не ломая бизнес-логику?

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍31👏1
✔️ Spring-тест: идемпотентность платёжного эндпоинта

Напишите защиту от двойного списания 👇

📦 Задание

Клиент при сетевом таймауте повторяет POST /payments и списание проходит дважды. Реализуйте идемпотентность по заголовку Idempotency-Key.

@PostMapping("/payments")
public PaymentResult pay(
@RequestHeader("Idempotency-Key") String key,
@RequestBody PaymentRequest request) {
// Ваша реализация
}


📋 Требования

— Повторный запрос с тем же ключом возвращает результат первого вызова и НЕ выполняет списание заново.
— Разные ключи → разные операции.
— Конкурентные запросы с одним ключом (двойной клик / параллельные ретраи) не должны привести к двойному выполнению.
— Ключ хранится с TTL (например, 24 часа).

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍2👏1
✔️ Java-тест: задачка с реального собеса

Наш подписчик прислал реальную задачу с собеса в Яндекс. Сможете решить? 👇

📦 Задание

Реализуйте банкомат и тесты к нему. Инициализируется набором купюр, умеет выдавать купюры под заданную сумму либо отвечать отказом. При выдаче купюры списываются с баланса.
/**
* Банкомат.
* Инициализируется набором купюр, выдаёт купюры под сумму либо отказывает.
* При выдаче купюры списываются с баланса.
*
* Номиналы:
* - 50, 100, 500, 1000, 5000 ₽
* - 20, 100, 500 EUR
*
* Валюты обрабатываются раздельно, обмен не поддерживается.
* Банкомат может использоваться многопоточно (резервирование выдачи).
* Поддержку многопоточности можно вынести в отдельную итерацию.
*/
public class ATM {
public ??? withdraw(???) {
// TODO
}
}


📋 Требования


— Сами определите, что withdraw принимает и что возвращает.
— Валюты считаются раздельно, обмена нет.
— Сумму, которую нельзя собрать имеющимися купюрами, отклоняем (частичная выдача недопустима).
— Покройте решение тестами.
— Бонус: сделайте безопасным для вызова из нескольких потоков.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍41👏1
✔️ Java-тест: медленный сервис кладёт всё приложение

Внешний API затупил на 30 секунд и наш сервис перестал отвечать целиком 👇

📦 Задание — code review

Ходим во внешний платёжный шлюз через RestTemplate.

@Configuration
public class HttpConfig {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

@Service
@RequiredArgsConstructor
public class PaymentGatewayClient {

private final RestTemplate restTemplate;

public GatewayResponse charge(ChargeRequest request) {
return restTemplate.postForObject(
"https://gateway.example.com/charge",
request,
GatewayResponse.class
);
}
}


▪️ Объясни

— Что происходит с пулом потоков Tomcat, когда внешний шлюз отвечает медленно или висит.
— Почему «ложится» всё приложение, хотя тормозит только один внешний вызов.
— Как настроить таймауты правильно (connect / read), зачем connection pool и где здесь место для timeout + circuit breaker / bulkhead.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍21🤔1
✔️ Spring-тест: рассылка ушла клиентам трижды

Подняли 3 реплики в k8s, и клиенты получили одно и то же письмо три раза 👇

📦 Задание — code review

Ежедневная рассылка счетов через @Scheduled.
@Component
@RequiredArgsConstructor
public class BillingScheduler {

private final InvoiceService invoiceService;

@Scheduled(cron = "0 0 9 * * *")
public void sendDailyInvoices() {
List<Invoice> due = invoiceService.findDueToday();
due.forEach(invoiceService::sendAndMarkSent);
}
}


▪️ Объясни

— Почему @Scheduled выполняется на каждой реплике и приводит к дублирующим отправкам.
— Почему «сначала проверим флаг isSent, потом отправим» не спасает от гонки между подами.
— Какие есть решения и их трейд-оффы.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍3🤔1
✔️ Java-тест: индексация списка в Map

Напишите метод для production-кода 👇

📦 Задание


Реализуйте метод, который строит индекс «email → пользователь»:
public Map<String, User> indexByEmail(List<User> users) {
// Ваша реализация
}


📋 Требования

— На вход может прийти null или пустой список → вернуть пустую Map.
— В списке встречаются пользователи с одинаковым email → при дубле оставить последнего (и обоснуйте политику).
— email может быть null → такие записи пропускать.
— Порядок итерации сохранять.

Ставьте → 🔥, если нравится формат. Если нет → 🤔

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥31👍1
✔️ Concurrency-тест: пул потоков копит задачи до OOM

Нагрузка выросла, latency пополз вверх, потом OutOfMemoryError 👇

📦 Задание — code review

Сервис обрабатывает входящие события асинхронно.
@Configuration
public class ExecutorConfig {

@Bean
public ExecutorService eventExecutor() {
return Executors.newFixedThreadPool(10);
}
}

@Service
@RequiredArgsConstructor
public class EventService {

private final ExecutorService eventExecutor;

public void handle(Event event) {
eventExecutor.submit(() -> process(event));
}
}


▪️ Объясни

— Какая очередь стоит за Executors.newFixedThreadPool и почему она опасна под нагрузкой.
— Почему задачи бесконтрольно «копятся» и система падает в OutOfMemoryError, а не начинает отбрасывать нагрузку.
— Как собрать ThreadPoolExecutor руками: ограниченная очередь, RejectedExecutionHandler, backpressure. Чем плох и newCachedThreadPool в этом сценарии.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍31
✔️ Java-тест: сортировка падает только на больших данных

Локально всё ок, на проде — IllegalArgumentException: Comparison method violates its general contract! 👇

📦 Задание — code review


Сортируем товары: сначала в наличии, потом по убыванию рейтинга.
products.sort((a, b) -> {
if (a.isInStock() && !b.isInStock()) return -1;
if (!a.isInStock() && b.isInStock()) return 1;
return (int) (b.getRating() - a.getRating()); // rating: double
});


▪️ Объясни

— Почему этот компаратор нарушает контракт (нетранзитивность / нарушение антисимметрии) и почему падает только на достаточно больших списках.
— Как переписать, чтобы было корректно и читаемо.

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1👏1