Java: проверено против непроверенного объяснения исключений

600

Я прочитал несколько сообщений в StackOverFlow о проверенных исключениях и исключениях без проверки. Я честно все еще не совсем уверен, как правильно их использовать.

Джошуа Блох в "Эффективной Java" сказал, что

Использовать проверенные исключения для восстанавливаемые условия и время выполнения исключения для ошибок программирования (Пункт 58 в 2-м издании)

Посмотрим, правильно ли я это понимаю.

Вот мое понимание проверенного исключения:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Является ли выше рассмотренное исключение?

2. Исключено ли исключение RuntimeException?

Вот мое понимание неконтролируемого исключения:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Теперь, не мог ли вышеуказанный код быть проверенным исключением? Я могу попытаться восстановить ситуацию так? Могу ли я? (Примечание: мой третий вопрос находится внутри catch выше)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Почему люди делают это?

public void someMethod throws Exception{

}

Почему они препятствуют возникновению исключения? Не лучше ли обрабатывать ошибку раньше? Почему пузыриться?

РЕДАКТИРОВАТЬ: Должен ли я вызывать точное исключение или маскировать его с помощью Exception?

Ниже приведены мои показания

В Java, когда я должен создать проверенное исключение и когда это должно быть исключение во время выполнения?

Когда выбрать отмеченные и непроверенные исключения

  • 5
    У меня есть отличный пример непроверенного исключения. У меня есть класс DataSeries который содержит данные, которые всегда должны оставаться в DataSeries порядке. Существует метод для добавления новой DataPoint в конец DataSeries . Если весь мой код работает правильно на протяжении всего проекта, никогда не следует добавлять DataPoint к концу, который имеет более DataPoint дату, чем тот, который уже находится в конце. Каждый модуль во всем проекте построен с этим трюизмом. Однако я проверяю это условие и выкидываю непроверенное исключение, если это происходит. Зачем? Если это произойдет, я хочу знать, кто это делает, и исправить это.
  • 1
    Чтобы добавить еще больше путаницы. Многие люди выступали за проверенные исключения ~ 10 лет назад, но в настоящее время взгляды все больше и больше переходят к «проверенные исключения - это плохо». (Однако я не согласен с этим)
Показать ещё 9 комментариев
Теги:
exception
runtimeexception
checked-exceptions
unchecked-exception

22 ответа

418
Лучший ответ

Многие говорят, что проверенные исключения (т.е. те, что вы должны явно поймать или ретронировать) не должны использоваться вообще. Например, они были исключены в С#, и большинство языков их не имеют. Таким образом, вы всегда можете отбросить подкласс RuntimeException (исключение без исключения)

Однако я считаю, что проверенные исключения полезны - они используются, когда вы хотите заставить пользователя вашего API думать о том, как справиться с исключительной ситуацией (если она восстанавливается). Просто проверенные исключения чрезмерно используются на платформе Java, что заставляет их ненавидеть их.

Вот мой расширенный просмотр по теме.

Что касается конкретных вопросов:

  • Является ли NumberFormatException рассмотренным исключением?
    Нет. NumberFormatException не проверяется (= является подклассом RuntimeException). Зачем? Я не знаю. (но должен был быть метод isValidInteger(..))

  • Является ли RuntimeException неконтролируемым исключением?
    Да, точно.

  • Что мне здесь делать?
    Это зависит от того, где этот код и что вы хотите. Если он находится в слое пользовательского интерфейса - поймайте его и покажите предупреждение; если он находится в сервисном слое - не поймайте его вообще - пусть он пузырится. Просто не проглатывайте исключение. Если в большинстве случаев возникает исключение, вы должны выбрать один из них:

    • запишите его и верните
    • rethrow it (объявить его брошенным методом)
    • построить новое исключение, передав текущий в конструкторе
  • Теперь, не мог ли приведенный выше код также быть проверенным исключением? Я могу попытаться восстановить ситуацию так? Могу ли я?
    Это могло быть. Но ничто не мешает вам также улавливать неконтролируемое исключение

  • Почему люди добавляют класс Exception в предложение throws?
    Чаще всего потому, что люди ленивы, чтобы подумать о том, что поймать и что нужно вернуть. Бросание Exception - это плохая практика, и ее следует избегать.

Увы, нет единого правила, позволяющего вам определять, когда нужно ловить, когда восстанавливать, когда использовать проверенные и когда использовать непроверенные исключения. Я согласен, что это вызывает много путаницы и много плохого кода. Общий принцип изложен Блохом (вы цитировали его часть). И общий принцип заключается в том, чтобы перестроить исключение на слой, где вы можете справиться с ним.

  • 34
    Что касается выдачи Exception, это не всегда потому, что люди ленивы, также часто вы, когда вы реализуете фреймворки, позволяете пользователям фреймворка генерировать любые исключения. Например, вы можете проверить подпись интерфейса Callable в JSE
  • 0
    @ Божо: Вы ответили 1, 2, 4 и 5 и назвали их 1, 2, 3 и 4. Правильный вопрос 3 скрыт в блоке кода.
Показать ещё 23 комментария
206

Является ли что-то "проверенным исключением", не имеет никакого отношения к тому, поймаете ли вы его или что вы делаете в блоке catch. Это свойство классов исключений. Все, что является подклассом Exception, за исключением RuntimeException и его подклассов, является проверенным исключением.

Компилятор Java заставляет вас либо проверять отмеченные исключения, либо объявлять их в сигнатуре метода. Предполагалось, что это улучшит безопасность программ, но мнение большинства кажется, что оно не стоит проблем дизайна, которые он создает.

Почему они допускают пузырь исключения вверх? Не ошибается ошибка, чем раньше лучше? Зачем пузыриться?

Потому что вся точка исключений. Без этой возможности вам не нужны исключения. Они позволяют обрабатывать ошибки на выбранном вами уровне, а не заставлять вас обращаться с ними в низкоуровневых методах, где они изначально происходят.

  • 3
    Спасибо! Я иногда выбрасываю исключения из своих методов из-за дерьма в принципе. Я, один из разработчиков в моей команде, хочу ввести недопустимое выражение xpath, чтобы они могли обработать исключение. В маловероятном случае они ловят исключение и ничего не делают, они услышат об этом в обзоре кода.
  • 10
    «Все, что является подклассом Throwable, за исключением RuntimeException и его подклассов, является проверенным исключением». - Ваше утверждение неверно. Ошибка также наследует Throwable и не проверяется.
Показать ещё 4 комментария
60
  1. Вышеуказанное считается проверенным исключением? Нет Тот факт, что вы обрабатываете исключение, не делает его Checked Exception если это RuntimeException.

  2. Является ли RuntimeExceptio n unchecked exception? да

Checked Exceptions являются subclasses java.lang.Exception Не отмеченные исключения являются subclasses java.lang.RuntimeException

Вызовы, выбрасывающие проверенные исключения, должны быть заключены в блок try {} или обработаны на уровне выше в вызывающей стороне метода. В этом случае текущий метод должен объявить, что он вызывает указанные исключения, чтобы вызывающие могли принять соответствующие меры для обработки исключения.

Надеюсь это поможет.

Q: я должен всплыть точное исключение или замаскировать его с помощью исключения?

A: Да, это очень хороший вопрос и важное соображение дизайна. Класс Exception является очень общим классом исключений и может использоваться, чтобы обернуть внутренние исключения низкого уровня. Вам лучше создать собственное исключение и обернуть его внутри. Но, и главное: никогда не скрывать первопричину. Например, Don't ever делай следующее -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Вместо этого сделайте следующее:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Искоренение первопричины скрывает фактическую причину, которая не подлежит восстановлению, - это кошмар для рабочих групп поддержки, которым все, что им предоставляется, - это журналы приложений и сообщения об ошибках. Хотя последний вариант лучше, но многие люди не используют его часто, потому что разработчики просто не могут передать исходное сообщение вызывающей стороне. Так что сделайте твердое замечание: Always pass on the actual exception обратно независимо от того, включено оно в какое-либо конкретное приложение или нет.

При попытке поймать RuntimeExceptions

RuntimeException как общее правило, не следует пытаться поймать. Они обычно сигнализируют об ошибке программирования и должны быть оставлены в покое. Вместо этого программист должен проверить состояние ошибки, прежде чем вызывать некоторый код, который может привести к RuntimeException. Например:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Это плохая практика программирования. Вместо этого нулевая проверка должна была быть сделана как -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Но бывают случаи, когда такая проверка ошибок стоит дорого, например, форматирование чисел, подумайте об этом -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Здесь проверка ошибок перед вызовом не стоит усилий, потому что она по сути означает дублирование всего кода преобразования строки в целое в методе parseInt() - и подвержена ошибкам, если реализована разработчиком. Так что лучше просто покончить с try-catch.

Таким образом, NullPointerException и NumberFormatException являются одновременно RuntimeExceptions, RuntimeExceptions NullPointerException должен быть заменен изящной нулевой проверкой, в то время как я рекомендую явно NumberFormatException чтобы избежать возможного введения подверженного ошибкам кода.

  • 0
    Спасибо. Еще один вопрос, когда вы всплываете exception , должен ли я всплыть точное исключение или замаскировать его с помощью Exception . Я пишу код поверх некоторого унаследованного кода, и везде возникают пузыри Exception . Интересно, это правильное поведение?
  • 1
    Это очень хороший и важный вопрос, отредактировал мой ответ, чтобы включить объяснение.
Показать ещё 3 комментария
17

1. Если вы не знаете об исключении, проверьте API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Да, и все исключения, которые его расширяют.

3. Не нужно ловить и бросать одно и то же исключение. В этом случае вы можете показать новый диалог с файлом.

4. FileNotFoundException уже является проверенным исключением.

5. Если ожидается, что метод, вызывающий someMethod, чтобы поймать исключение, последний может быть выброшен. Он просто "передает мяч". Примером его использования может быть, если вы хотите бросить его в свои собственные частные методы и вместо этого обработать исключение в своем общедоступном методе.

Хорошее чтение - это сам документ Oracle: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Почему дизайнеры решили заставить метод указать все неперехваченные проверенные исключения, которые могут быть выбраны в пределах его области? Любое исключение, которое может быть выбрано методом, является частью интерфейса публичного программирования метода. Те, кто вызывает метод, должны знать об исключениях, которые метод может бросить, чтобы они могли решить, что с ними делать. Эти исключения являются такой же частью интерфейса программирования метода, как и его параметры и возвращаемое значение.

Следующий вопрос может быть следующим: "Если это так хорошо, чтобы документировать API-интерфейс метода, включая исключения, которые он может использовать, почему бы и не указывать исключения времени выполнения?" Исключения в Runtime представляют проблемы, которые являются результатом проблемы программирования, и, как таковой, клиентский код API не может разумно ожидать восстановления от них или для их обработки каким-либо образом. К таким проблемам относятся арифметические исключения, такие как деление на ноль; исключения указателя, например, попытки доступа к объекту посредством нулевой ссылки; и исключения индексирования, такие как попытка доступа к элементу массива через слишком большой или слишком большой индекс.

Также существует важная информация в Спецификация языка Java:

Проверенные классы исключений, названные в предложении throws, являются частью контракта между разработчиком и пользователем метода или конструктора.

Инициатива IMHO заключается в том, что вы можете поймать любой RuntimeException, но вам не требуется, и на самом деле реализация не требуется для поддержания тех же не проверенных исключений, которые были выбраны, поскольку они не являются частью контракта.

  • 0
    Спасибо. Еще один вопрос, когда вы всплываете exception , должен ли я всплыть точное исключение или замаскировать его с помощью Exception . Я пишу код поверх некоторого унаследованного кода, и везде возникают пузыри Exception . Интересно, это правильное поведение?
  • 1
    @ Гарри, я позволю людям с большим знанием, чем я, ответить на это: stackoverflow.com/questions/409563/…
Показать ещё 1 комментарий
9

1) Нет, исключение NumberFormatException является неконтролируемым Исключением. Даже если вы поймали его (вы не обязаны), он не установлен. Это потому, что это подкласс IllegalArgumentException, который является подклассом RuntimeException.

2) RuntimeException является корнем всех непроверенных исключений. Каждый подкласс RuntimeException не установлен. Все остальные исключения и Throwables проверяются, за исключением ошибок (которые попадают под Throwable).

3/4) Вы можете предупредить пользователя о том, что они выбрали несуществующий файл и попросят новый. Или просто прекратите информировать пользователя о том, что они ввели что-то недействительное.

5) Бросание и ловлю "Исключения" - это плохая практика. Но в более общем плане вы можете использовать другие исключения, чтобы вызывающий мог решить, как с этим бороться. Например, если вы написали библиотеку, чтобы обрабатывать чтение некоторых файлов, и ваш метод был передан несуществующим файлом, вы не знаете, как с этим справиться. Вызывающий абонент хочет снова спросить или уйти? Таким образом, вы бросаете Исключение вверх по цепочке обратно к вызывающему.

Во многих случаях неконтролируемое исключение происходит, потому что программист не проверял ввод (в случае NumberFormatException в вашем первом вопросе). Вот почему его необязательно улавливать, потому что есть более элегантные способы избежать генерирования этих исключений.

  • 0
    Спасибо. Еще один вопрос, когда вы всплываете exception , должен ли я всплыть точное исключение или замаскировать его с помощью Exception . Я пишу код поверх некоторого унаследованного кода, и везде возникают пузыри Exception . Интересно, это правильное поведение?
  • 0
    Вы можете либо просто использовать свой метод, либо выдавать Exception (что не идеально). Или поймайте Exception и добавьте лучшее Exception (например, IOException или что-то в этом роде). Все исключения могут принимать исключение в своем конструкторе как «причину», поэтому вы должны использовать это.
7

Проверено - Предполагается, что произойдет. Проверено во время компиляции.

Например, FileOperations

Не проверено - из-за плохих данных. Проверено во время выполнения.

Например,

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Здесь исключение связано с плохими данными и никоим образом не может быть определено во время компиляции.

5

Проверенные исключения проверяются во время компиляции JVM и связаны с ресурсами (файлы/db/stream/socket и т.д.). Мотивом проверенного исключения является то, что во время компиляции, если ресурсы недоступны, приложение должно определить альтернативное поведение для обработки этого в блоке catch/finally.

Исключенные исключения - это чисто программные ошибки, неправильный расчет, нулевые данные или даже сбои в бизнес-логике могут привести к исключениям во время выполнения. Его абсолютно нормально обрабатывать/исключать исключенные исключения из кода.

Объяснение взято из http://coder2design.com/java-interview-questions/

3

Исключения времени выполнения Исключения исключений относятся к неконтролируемым исключениям. Все остальные исключения проверяются исключения, и они не выводятся из java.lang.RuntimeException.

Проверенные исключения Проверенное исключение должно быть обнаружено где-то в вашем коде. Если вы вызываете метод, который выдает проверенное исключение, но вы не поймаете проверенное исключение где-то ваш код не будет компилироваться. Вот почему они называются проверенными Исключения: компилятор проверяет, чтобы они были обработаны или объявлены.

Ряд методов в Java API выдает проверенные исключения, поэтому вы часто пишете обработчики исключений, чтобы справляться с исключениями, генерируемыми методами, которые вы не пишете.

3

Мое абсолютное любимое описание разницы между отмененными и проверенными исключениями представлено в статье "Учебное пособие по Java", " Unchecked Exceptions - the Controversy" (извините за то, что все элементарные на этом посту - но, эй, основы иногда лучшие):

Вот руководство к нижней строке: если клиент может разумно ожидается, что он восстановится после исключения, сделайте это проверенным исключением. Если клиент не может ничего сделать для восстановления из исключения, сделайте его исключенное исключение

Сердце "типа исключения для броска" является семантическим (в некоторой степени), и приведенная выше цитата дает и отличную рекомендацию (следовательно, меня все еще смущает мысль о том, что С# избавился от проверенных исключений - в частности, как Лисков утверждает их полезность).

Остальное становится логичным: какие исключения компилятор ожидает от меня ответа, явно? Те, из которых вы ожидаете, что клиент восстановится.

2

Я просто хочу добавить некоторые рассуждения о том, что вы не используете проверенные исключения вообще. Это не полный ответ, но я чувствую, что он отвечает на часть вашего вопроса и дополняет многие другие ответы.

Когда проверяются исключения, существует throws CheckedException где-то в сигнатуре метода (CheckedException может быть любым проверенным исключением). Подпись НЕ выбрасывает исключение, бросание Исключения являются аспектом реализации. Интерфейсы, сигнатуры методов, родительские классы, все эти вещи НЕ должны зависеть от их реализаций. Использование проверенных Исключений здесь (фактически тот факт, что вы должны объявить throws в сигнатуре метода) связывает ваши интерфейсы более высокого уровня с вашими реализациями этих интерфейсов.

Позвольте мне показать вам пример.

Пусть у нас красивый и чистый интерфейс

public interface IFoo {
    public void foo();
}

Теперь мы можем написать много реализаций метода foo(), как эти

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Класс Foo отлично подходит. Теперь сделаем первую попытку класса Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Этот класс Bar не будет компилироваться. Поскольку InterruptedException является проверенным исключением, вы должны либо его захватить (с помощью try-catch внутри метода foo()), либо объявить, что вы его бросаете (добавление throws InterruptedException к сигнатуре метода). Поскольку я не хочу фиксировать это исключение здесь (я хочу, чтобы он распространялся вверх, чтобы я мог правильно справиться с ним где-то в другом месте), пусть меняет подпись.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Этот класс Bar не будет компилироваться! Метод bar foo() НЕ переопределяет метод IFoo foo(), поскольку их подписи разные. Я мог бы удалить аннотацию @Override, но я хочу запрограммировать интерфейс IFoo как IFoo foo;, а затем решить, какую реализацию я хочу использовать, например foo = new Bar();. Если метод bar foo() не переопределяет IFoo-метод foo, когда я делаю foo.foo();, он не будет вызывать реализацию бана foo().

Чтобы сделать бар public void foo() throws InterruptedException переопределить IFoo public void foo(), я ДОЛЖЕН добавить throws InterruptedException к сигнатуре метода IFoo. Это, однако, вызовет проблемы с моим классом Foo, так как его сигнатура метода foo() отличается от сигнатуры метода IFoo. Кроме того, если бы я добавил throws InterruptedException в метод Foo foo(), я бы получил еще одну ошибку, указав, что метод Foo foo() объявляет, что он генерирует прерывание Exception, но никогда не генерирует прерывание Exception.

Как вы можете видеть (если я сделал приличную работу при объяснении этого материала), тот факт, что я бросаю проверенное исключение, такое как InterruptedException, заставляет меня привязать мой интерфейс IFoo к одной из его реализаций, что, в свою очередь, вызывает хаос в других реализациях IFoo!

Это одна из главных причин, по которым проверенные исключения BAD. В шапках.

Одним из решений является захват проверенного исключения, перенос его в неконтролируемое исключение и исключение неконтролируемого исключения.

  • 2
    Да, это плохо, потому что ты сказал, что не хочешь его поймать. Но чтобы не повлиять на подпись IFOO, вам придется. Я бы предпочел сделать это и двигаться дальше, а не перебалансировать все мои сигнатуры интерфейсов, чтобы избежать перехвата исключения (только потому, что исключения ПЛОХО).
  • 0
    Да я согласен. Я был немного неясен о чем-то. Я хочу, чтобы исключение распространялось, поэтому я могу иметь дело с этим где-то еще. Одним из решений является перехват InterruptedException и создание непроверенного исключения. т.е. мы избегаем проверенных исключений и пропускаем непроверенные исключения (даже если они имеют смысл только как обертка)
Показать ещё 3 комментария
2
  • Java различает две категории исключений (проверено и не проверено).
  • Java применяет улов или объявленное требование для проверенных исключений.
  • Тип исключения определяет, будет ли исключение отмечено или не отмечено.
  • Все типы исключений, которые являются прямыми или косвенными subclasses класса RuntimeException являются непроверенными исключениями.
  • Все классы, которые наследуются от класса Exception но не от RuntimeException, считаются checked exceptions.
  • Классы, которые наследуются от класса Error, считаются непроверенными.
  • Компилятор проверяет каждый вызов метода и замедление, чтобы определить, вызывает ли метод checked exception.
    • В этом случае компилятор гарантирует, что исключение будет перехвачено или объявлено в предложении throws.
  • Чтобы удовлетворить объявленную часть требования catch-or-Declare, метод, который генерирует исключение, должен предоставить предложение throws, содержащее checked-exception.
  • Классы Exception определяются для проверки, когда они считаются достаточно важными для отлова или объявления.
2

Чтобы ответить на окончательный вопрос (остальные, как представляется, полностью ответили выше), "Должен ли я всплывать точное исключение или маскировать его с помощью исключения?"

Я предполагаю, что вы имеете в виду что-то вроде этого:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Нет, всегда указывайте наиболее точное исключение или список таких. Исключения, которые вы объявляете своим методом, способным метать, являются частью контракта между вашим методом и вызывающим. Бросок "FileNotFoundException" означает, что возможно, что имя файла недопустимо, и файл не будет найден; вызывающему нужно будет обращаться с этим разумно. Бросать "Исключение" означает "Эй, sh * t бывает. Сделка". Это очень плохой API.

В комментариях к первой статье есть несколько примеров, где "throws Exception" является допустимым и разумным объявлением, но это не относится к большинству "нормальных" кодов, которые вы когда-либо будете писать.

  • 0
    Точно, сделайте ваше объявление об исключении чека частью документации вашего кода, а также помогите человеку, использующему ваше программное обеспечение.
1

Короче говоря, исключения, которые ваш модуль или модули выше должны обрабатывать во время выполнения, называются проверенными исключениями; другие являются непроверенными исключениями, которые являются либо RuntimeException либо Error.

В этом видео объясняются проверенные и непроверенные исключения в Java:
https://www.youtube.com/watch?v=ue2pOqLaArw

1

Просто отметим, что если вы выбрали проверенное исключение в коде, а catch - несколько уровней выше, вам нужно объявить исключение в сигнатуре каждого метода между вами и catch. Таким образом, инкапсуляция нарушена, потому что все функции в пути throw должны знать о деталях этого исключения.

1

Я думаю, что проверенные исключения - хорошее напоминание разработчику, который использует внешнюю библиотеку, что в исключительных ситуациях все может пойти не так, как с кодом из этой библиотеки.

Подробнее о проверенных и непроверенных исключениях читайте здесь http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/

1

Вот простое правило, которое может помочь вам решить. Это связано с тем, как интерфейсы используются в Java.

Возьмите свой класс и представьте себе создание интерфейса для него, чтобы интерфейс описывал функциональность класса, но ни одна из базовой реализации (как интерфейс). Представьте, возможно, что вы могли бы реализовать класс по-другому.

Посмотрите на методы интерфейса и рассмотрите исключения, которые они могли бы бросить:

Если исключение может быть выбрано методом, независимо от базовой реализации (другими словами, оно описывает только функциональность), то это, вероятно, должно быть проверенным исключением в интерфейсе.

Если исключение вызвано базовой реализацией, оно не должно быть в интерфейсе. Таким образом, это должно быть либо исключение из исключения в вашем классе (поскольку необработанные исключения не должны появляться в сигнатуре интерфейса), либо вы должны обернуть его и перебросить как исключенное исключение, которое является частью метода интерфейса.

Чтобы решить, следует ли вам обертывать и реконструировать, вы должны снова рассмотреть вопрос о том, нужно ли пользователю интерфейса обрабатывать условие исключения немедленно, или исключение является настолько общим, что вы ничего не можете с этим поделать и он должен распространять стек. Является ли обернутое исключение понятным, когда оно выражается как функциональность нового интерфейса, который вы определяете, или это просто носитель для мешка возможных условий ошибки, который также может случиться с другими методами? Если первое, оно все равно может быть проверенным исключением, в противном случае оно должно быть отменено.

Обычно вы не должны планировать "пузырьковые" исключения (улов и ретроф). Либо исключение должно обрабатываться вызывающим (в этом случае оно проверено), либо оно должно полностью пройти до обработчика высокого уровня (в этом случае это проще всего, если он не установлен).

1

Почему они препятствуют возникновению исключения? Не лучше ли обрабатывать ошибку раньше? Почему пузыриться?

Например, скажем, у вас есть клиент-серверное приложение, и клиент сделал запрос на какой-то ресурс, который не может быть обнаружен или что-то еще ошибка может произойти на стороне сервера при обработке запроса пользователя, сервер обязан сообщать клиенту, почему он не мог получить то, о чем он просил, поэтому для достижения этого на стороне сервера код записывается для исключения исключения с помощью throw вместо того, чтобы глотать или обрабатывать его. Если сервер обрабатывает его/проглатывает, тогда не будет возможности сообщить клиенту, что произошла ошибка.

Примечание. Чтобы дать четкое описание того, что произошло при возникновении ошибки, мы можем создать наш собственный объект Exception и передать его клиенту.

  • 0
    Хорошая точка зрения. Это означает, что он должен подняться на самый ответственный уровень, который контролирует логический поток и контролирует бизнес-логику приложения. Например, для уровня базы данных было бы невозможно сообщить клиенту, что что-то критическое отсутствует или не отвечает. Когда он поднимается до самого верхнего уровня сервера, тогда просто обновить представление клиента критическим сообщением об ошибке.
0

Основное различие между проверенным и неконтролируемым исключением заключается в том, что проверенные исключения проверяются во время компиляции, в то время как исключенные исключения проверяются во время выполнения.

Что такое проверенные исключения? Проверенные исключения проверяются во время компиляции. Это означает, что если метод выбрасывает проверенное исключение, он должен обрабатывать исключение, используя блок try-catch, или должен объявлять исключение, используя ключевое слово throw, иначе программа выдаст ошибку компиляции.

Давайте рассмотрим это с помощью примера:

Проверенный пример исключения В этом примере мы читаем файл myfile.txt и отображаем его содержимое на экране. В этой программе есть три места, где выбрано исключенное исключение, как указано в комментариях ниже. FileInputStream, который используется для указания пути и имени файла, выдает FileNotFoundException. Метод read(), который считывает содержимое файла, генерирует IOException и метод close(), который закрывает входной поток файла, также вызывает исключение IOException.

   import java.io.*;
    class Example {  
    public static void main(String args[]) 
  {
  FileInputStream fis = null;
  /*This constructor FileInputStream(File filename)
 * throws FileNotFoundException which is a checked
 * exception
     */
    fis = new FileInputStream("B:/myfile.txt"); 
  int k; 

  /* Method read() of FileInputStream class also 
throws 
 * a checked exception: IOException
     */
  while(( k = fis.read() ) != -1) 
  { 
    System.out.print((char)k); 
    } 

/*The method close() closes the file input stream
 * It throws IOException*/
   fis.close();     
  }
  }

Вывод:

Исключение в потоке "main" java.lang.Error: нерешенные проблемы компиляции: необработанный тип исключения FileNotFoundException Необработанный тип исключения IOException Необработанный тип исключения IOException Почему эта ошибка компиляции? Как я уже упоминал в начале, проверенные исключения проверяются во время компиляции. Поскольку мы не обрабатывали/не объявляли исключения, наша программа давала ошибку компиляции. Как устранить ошибку? Существует два способа избежать этой ошибки. Мы увидим оба пути один за другим.

Метод 1: объявить исключение, используя ключевое слово throw. Как известно, все три случая отмеченных исключений находятся внутри метода main(), поэтому один из способов избежать ошибки компиляции: объявить исключение в методе, используя ключевое слово throw. Возможно, вы думаете, что наш код бросает FileNotFoundException и IOException и то, почему мы объявляем только IOException. Причина в том, что IOException является родительским классом FileNotFoundException, поэтому он по умолчанию охватывает это. Если вы хотите, вы можете объявить их как это public static void main (String args []), выдает IOException, FileNotFoundException.

   import java.io.*;
   class Example {  
   public static void main(String args[]) throws 
   IOException
   {
  FileInputStream fis = null;
  fis = new FileInputStream("B:/myfile.txt"); 
  int k; 

  while(( k = fis.read() ) != -1) 
  { 
   System.out.print((char)k); 
  } 
  fis.close();  
    }
   }

Выход: содержимое файла отображается на экране.

Способ 2. Обработать их с помощью блоков try-catch. Подход, который мы использовали выше, не очень хорош. Это не лучшая практика обработки исключений. Вы должны дать содержательное сообщение для каждого типа исключения, чтобы кому-то было легко понять эту ошибку. Код должен выглядеть следующим образом:

  import java.io.*;
  class Example {  
  public static void main(String args[])
  {
  FileInputStream fis = null;
  try{
    fis = new FileInputStream("B:/myfile.txt"); 
  }catch(FileNotFoundException fnfe){
        System.out.println("The specified file is not 
   " +
        "present at the given path");
   }
   int k; 
   try{
    while(( k = fis.read() ) != -1) 
    { 
    System.out.print((char)k); 
    } 
    fis.close(); 
    }catch(IOException ioe){
    System.out.println("I/O error occurred: "+ioe);
    }
    }
    }

Этот код будет работать нормально и отобразит содержимое файла.

Вот несколько других проверенных исключений -

SQLException IOException ClassNotFoundException InvocationTargetException Что такое исключенные исключения? Неконтролируемые исключения не проверяются во время компиляции. Это означает, что если ваша программа выбрасывает исключение, и даже если вы не обработали/не объявили это исключение, программа не даст ошибку компиляции. В большинстве случаев это исключение происходит из-за плохих данных, предоставленных пользователем во время взаимодействия с пользовательской программой. Программист должен заранее судить об условиях, которые могут вызывать такие исключения и обрабатывать их надлежащим образом. Все исключенные исключения являются прямыми подклассами класса RuntimeException.

Давайте рассмотрим это на примере:

Непроверенный пример исключения

   class Example {  
   public static void main(String args[])
   {
   int num1=10;
   int num2=0;
   /*Since I'm dividing an integer with 0
   * it should throw ArithmeticException
     */
   int res=num1/num2;
   System.out.println(res);
   }
   }

Если вы скомпилируете этот код, он успешно скомпилируется, но когда вы его запустите, он выбросит ArithmeticException. Это ясно показывает, что неконтролируемые исключения не проверяются во время компиляции, они встречаются во время выполнения. Давайте посмотрим другой пример.

  class Example {  
  public static void main(String args[])
  {
  int arr[] ={1,2,3,4,5};
   /* My array has only 5 elements but we are trying 
   to 
      * display the value of 8th element. It should 
  throw
   * ArrayIndexOutOfBoundsException
     */
  System.out.println(arr[7]);
  }
  }

Этот код также будет успешно скомпилирован, поскольку ArrayIndexOutOfBoundsException также является неконтролируемым исключением. Примечание. Это не значит, что компилятор не проверяет эти исключения, поэтому мы не должны их обрабатывать. На самом деле мы должны обращаться с ними более тщательно. Например, например, в приведенном выше примере должно быть сообщение об ошибке для пользователя, что они пытаются отобразить значение, которое не существует в массиве, чтобы пользователь мог исправить проблему.

  class Example {  
   public static void main(String args[]) {
  try{
   int arr[] ={1,2,3,4,5};
   System.out.println(arr[7]);
   }
    catch(ArrayIndexOutOfBoundsException e){
   System.out.println("The specified index does not 
   exist " +
    "in array. Please correct the error.");
    }
    }
    }

Вывод:

Указанный индекс не существует в массиве. Исправьте ошибку. Вот несколько неконтролируемых классов исключений:

NullPointerException ArrayIndexOutOfBoundsException ArithmeticException IllegalArgumentException NumberFormatException

0

Все это проверенные исключения. Непроверенные исключения - это подклассы RuntimeException. Решение заключается не в том, как обращаться с ними, это должно привести к их коду. Если вы не хотите, чтобы компилятор сообщал вам о том, что вы не обработали исключение, вы используете исключение исключаемого (подкласс RuntimeException). Они должны быть сохранены для ситуаций, которые невозможно восстановить, например, из-за ошибок в памяти и т.д.

  • 0
    гм. если NumberFormatException является проверенным исключением, как вы говорите, не противоречит ли оно тому, что оно унаследовано от RuntimeException ?
  • 0
    Извините, мне было не очень понятно. Я имел в виду исключение FileNotFoundException, а не NumberFormatException. Основываясь на его # 2 и # 4, казалось, что он думал, что Checked vs. Unchecked был основан на том, как вы обработали исключение после его перехвата. Не так, как это было определено.
-1

Проверенные исключения:

  • Исключения, которые проверяются компилятором для плавного выполнения программы во время выполнения, называются Checked Exception.

  • Это происходит во время компиляции.

  • Если они не обрабатываются должным образом, они выдадут ошибку времени компиляции (Not Exception).
  • Все подклассы класса Exception, кроме RuntimeException, являются проверенными исключениями.

    Гипотетический пример. Предположим, что вы покидаете свой дом для экзамена, но если вы проверите, взял ли вы свой билет на дом дома (время компиляции), то в экзаменационном зале не будет никаких проблем (среда).

Неконтролируемое исключение:

  • Исключения, которые не проверяются компилятором, называются Unchecked Exceptions.

  • Это происходит во время выполнения.

  • Если эти исключения не обрабатываются должным образом, они не дают ошибку времени компиляции. Но программа будет завершена досрочно во время выполнения.

  • Все подклассы RunTimeException и Error являются исключенными исключениями.

    Гипотетический пример. Предположим, что вы находитесь в вашем зале для экзаменов, но почему-то в вашей школе произошел пожар (означает во время выполнения), где вы не можете ничего делать в то время, но предостережения могут быть сделаны раньше ( время компиляции).

-1

Если кто-то заботится о еще одном доказательстве, чтобы не нравиться проверенные исключения, см. первые несколько абзацев популярной библиотеки JSON:

"Хотя это проверенное исключение, оно редко восстанавливается. Большинство вызывающих абонентов должны просто обернуть это исключение в неконтролируемое исключение и ретронировать:"

Итак, почему в мире кто-нибудь заставит разработчиков продолжать проверять исключение, если мы должны "просто обернуть его"? лол

http://developer.android.com/reference/org/json/JSONException.html

  • 4
    Потому что только большинство абонентов, а не все абоненты, должны переносить и отбрасывать. Тот факт, что исключение проверено, означает, что вызывающий абонент должен думать о том, являются ли они одним из "большинства" вызывающих абонентов или одним из меньшинств, которые могут и должны обработать исключение.
  • 1
    Если вам нравится проверять ошибки для каждого звонка, который вы делаете, вернитесь к C. Исключения - это способ отделить нормальное выполнение программы от ненормального, не загрязняя ваш код. Исключения гарантируют, что вы не можете игнорировать ошибку на каком-то уровне .
-2

Все исключения должны быть проверены исключениями.

  • Исключенные исключения - это неограниченные пересылки. И неограниченные gotos считаются плохими.

  • Непроверенные исключения прерывают инкапсуляцию. Чтобы правильно их обработать, все функции в дереве вызовов между метателем и ловушкой должны быть известны, чтобы избежать ошибок.

  • Исключения - это ошибки в функции, которая бросает их, но не ошибки в функции, которая их обрабатывает. Цель исключений - предоставить программе второй шанс, отложив решение о том, является ли это ошибкой или нет в другом контексте. Это только в другом контексте может быть принято правильное решение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню