24Чем отличаются проверяемые и непроверяемые исключения?
Проверяемые классы throwable — это классы вне иерархий RuntimeException и Error; обычные проверяемые исключения приложения наследуются от Exception, но не от RuntimeException. Компилятор требует обработать или объявить проверяемые исключения. RuntimeException, Error и их подклассы являются непроверяемыми. Error обычно обозначает серьёзные проблемы среды выполнения или системы, а не обычный сбой приложения, после которого можно восстановиться. Проверяемые исключения подходят для ситуаций с возможностью восстановления на границах API. Непроверяемые — для ошибок программирования, недопустимых состояний и нарушений контрактов. В современном сервисном коде команды часто избегают чрезмерного использования проверяемых исключений, поскольку они распространяются по слоям и загромождают код.
void load() throws IOException {
// ...
}
throw new IllegalArgumentException("Invalid id");
Попробовать ответить на вопрос AI-тренеру
25Чем throw, throws и try-with-resources отличаются?
throw непосредственно выбрасывает exception. throws объявляет possible exception в method signature. try-with-resources автоматически закрывает AutoCloseable resources в reverse order. Если exception возник и в основном коде, и при close, вторичная ошибка сохраняется как suppressed exception. Это предпочтительнее ручного finally при нескольких ресурсах.
throw new IllegalArgumentException("Invalid id");
void readFile() throws IOException {}
try (var reader = Files.newBufferedReader(path)) {
return reader.readLine();
}
Попробовать ответить на вопрос AI-тренеру
26Что такое Stream API?
Stream API позволяет declaratively обрабатывать sequences. Intermediate operations вроде filter/map/sorted lazy; terminal operations вроде toList/collect/reduce/forEach запускают выполнение. Stream не является collection, обычно используется один раз и лучше работает с pure functions без side effects. parallelStream не гарантирует ускорение и может ухудшить performance или correctness.
List<String> names = users.stream()
.filter(User::isActive)
.sorted(Comparator.comparing(User::getName))
.map(User::getName)
.toList();
Попробовать ответить на вопрос AI-тренеру
27Что такое Optional и когда его применять?
Optional<T> явно представляет отсутствие результата и хорошо подходит для return values. Полезные методы: map, flatMap, filter, orElse, orElseGet, orElseThrow. orElse вычисляет argument всегда, а supplier в orElseGet только если value absent. Optional обычно не рекомендуют без необходимости использовать в entity fields, method parameters и serialized DTO.
Optional<User> user = repository.findById(id);
String name = user
.map(User::getName)
.orElse("Unknown");
optional.orElse(expensiveOperation());
optional.orElseGet(() -> expensiveOperation());
Попробовать ответить на вопрос AI-тренеру
28Что гарантируют synchronized, volatile и atomic-классы?
synchronized обеспечивает mutual exclusion и happens-before. volatile гарантирует visibility последних записей и ограничивает reordering, но не делает составные операции atomic. Atomic classes дают одиночные atomic operations, например incrementAndGet. Для нескольких связанных изменений используют lock/synchronized, для simple state flag — volatile, для counters — AtomicInteger или LongAdder при высокой конкуренции.
synchronized (lock) {
counter++;
}
private volatile boolean running = true;
AtomicInteger counter = new AtomicInteger();
counter.incrementAndGet();
Попробовать ответить на вопрос AI-тренеру
29Что такое race condition, deadlock и thread safety?
Race condition возникает, когда result зависит от unpredictable order выполнения threads. Deadlock — когда threads бесконечно ждут resources друг друга. Для thread safety уменьшают shared mutable state, соблюдают единый lock order, сокращают critical sections, не вызывают external code под lock, используют immutable objects, concurrent collections, timeouts и message passing. Thread safety — свойство всего protocol доступа к state.
Попробовать ответить на вопрос AI-тренеру
30Чем ExecutorService, CompletableFuture и virtual threads отличаются?
ExecutorService управляет thread pool и task execution. CompletableFuture помогает compose asynchronous operations. Virtual threads — lightweight JVM threads, удобные для большого количества blocking I/O tasks. Они упрощают thread-per-request model, но не ускоряют CPU-bound work, не отменяют лимиты базы/внешних ресурсов и не делают mutable state thread-safe автоматически.
try (var executor = Executors.newFixedThreadPool(4)) {
Future<Integer> future = executor.submit(() -> calculate());
int result = future.get();
}
CompletableFuture<User> userFuture =
CompletableFuture.supplyAsync(this::loadUser)
.thenApply(this::enrichUser)
.exceptionally(error -> fallbackUser());
try (var executor =
Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> handleRequest());
}
Попробовать ответить на вопрос AI-тренеру