Thread.sleep в лямбде Runnable — этот код не компилируется
Вопрос звучит безобидно: «что выведет этот код», даёт сто потоков, которые дергают ++ и -- над общим int[], а логику потока оборачивают в лямбду с Thread.sleep внутри. Кандидат начинает рассуждать про гонку, видимость, атомарность — и упускает, что до выполнения дело не дойдёт вообще.
Runnable.run() объявлен без throws. Thread.sleep бросает проверяемое InterruptedException. Лямбда, реализующая run(), обязана соответствовать его сигнатуре — проверяемое исключение внутри без обработки не компилируется.
Runnable task = () -> { try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // тело счетчика };
Без try-catch компилятор выдаст ошибку «unhandled exception» прямо на строке с Thread.sleep, и вопрос про гонку над int[] становится неактуален — до рантайма дело не доходит.
Это ловушка на внимательность: вопрос маскируется под «что выведет», а по факту проверяет, помнишь ли ты разницу между checked и unchecked исключениями и то, что лямбда наследует контракт функционального интерфейса целиком, включая throws. Следом обычно спрашивают: а если бы run() объявлял throws Exception, что изменилось бы с точки зрения совместимости с Runnable? Ответ — ничего не изменилось бы, потому что тогда это уже не Runnable, а другой функциональный интерфейс, например Callable.
Проверяемые исключения — это контракт сигнатуры, и лямбда не может его расширить, даже если тело выглядит невинно.
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки