Например, поэтому:
    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 оказывается пустой тратой времени, ибо по-настоящему никакой проблемы не решает.