Например, поэтому:
public ChangeResult putChanges(
@ApiParam(value = "Access token", required = true)
@HeaderParam("X-Access-Token") AccessToken token,
@ApiParam(value = "Request time")
@QueryParam("request_time") Long requestTime,
ListOfChanges listOfChanges
) throws WebTokenException, EntityNotFoundException, EntityAlreadyExistException,
InvalidParameterException, UploadServiceException, ParentFolderNotExistException,
LibraryNotExistException, ConstraintViolationException, UnfinishedProcessExistsException,
MediaFileNotExistException, PlaylistNotExistException { ... }
(это из одного проекта 5-летней давности)
И самое главное - такая классификация "сортов" исключений совершенно не помогает сделать код ни надёжным, ни сопровождаемым!
Почему? Потому что действительно интересная классификация ошибок "неожиданные/ожидаемые, ошибки бизнес-логики/ошибки реализации" ортогональна иерархии исключений, и не все ошибки выражаются исключениями.
Гораздо интереснее то, что вот такая-то функция вообще имеет эффект, и если этот эффект есть бросание исключения, то достаточно описания именно эффекта, а какое конкретно исключение было/будет выброшено - вопрос десятый.
И раз уж функция в IO, то описание того, что функция бросает исключение не добавляет и не убавляет из этой информации ничего - всё равно в IO может произойти всё, что угодно.
То есть вся эта работа по тщательному описанию исключений, выстраивания иерархии и расстановке try-catch оказывается пустой тратой времени, ибо по-настоящему никакой проблемы не решает.