Когда использовать броски в объявлении метода Java?

82

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

    public void method() throws SomeException
    {
         // method body here
    }

Из чтения некоторых похожих сообщений я понял, что throws используется как своего рода объявление, которое SomeException может быть сгенерировано во время выполнения метода.

Мое замешательство вызвано каким-то кодом, который выглядел так:

     public void method() throws IOException
     {
          try
          {
               BufferedReader br = new BufferedReader(new FileReader("file.txt"));
          }
          catch(IOException e)
          {
               System.out.println(e.getMessage());
          }
     }

Есть ли причина, по которой вы хотели бы использовать броски в этом примере? Кажется, что если вы просто выполняете базовую обработку исключений чего-то вроде IOException, вам просто понадобится блок try / catch и все.

JBranchaud
источник

Ответы:

79

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

Обычно, если вы не собираетесь ничего делать за исключением, вы не должны его ловить.

Самое опасное, что вы можете сделать, - это поймать исключение и ничего не делать с ним.

Хорошее обсуждение того, когда уместно создавать исключения, находится здесь

Когда вызывать исключение?

hvgotcodes
источник
2
Следует ли также объявлять непроверенные исключения в сигнатуре метода с помощью «throws» или на практике использовать «throws» только для проверенных исключений?
Cody
Этот ответ не затрагивает непосредственно центральный аспект вопроса: использование throwsключевого слова.
Брент Брэдберн
@hvgotcodes Что произойдет, если я поймаю исключение и ничего не сделаю?
Manoj
@manoj, вы рискуете сломаться и не сумеете понять это, потому что важная информация потеряна. Бывают случаи (не обязательно java), когда можно поймать исключение и ничего не делать, но это должно быть задокументировано. Например, в javascript вы можете попробовать вызвать функциональность, которая может отсутствовать в зависимости от браузера. Это не обязательно ошибка, требующая внимания.
hvgotcodes
22

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

См. Здесь некоторые сведения о проверенных и неотмеченных исключениях: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Если метод перехватывает исключение и обрабатывает его внутренне (как в вашем втором примере), тогда нет необходимости включать предложение throws.

Шейн Белл
источник
9

Код, на который вы смотрели, не идеален. Вам следует либо:

  1. Перехватить исключение и обработать его; в этом случае throwsэто необязательно.

  2. Удалите try/catch; в этом случае исключение будет обработано вызывающим методом.

  3. Поймать исключение, возможно, выполнить какое-то действие, а затем повторно выбросить исключение (а не только сообщение)

Дамо
источник
2

Вы правы, в этом примере throwsлишнее. Возможно, это было оставлено там из какой-то предыдущей реализации - возможно, исключение было изначально сгенерировано, а не поймано в блоке catch.

RevBingo
источник
2

Код, который вы опубликовали, неверен, он должен генерировать исключение, если улавливает конкретное исключение, чтобы обработать IOException, но генерировать не уловленные исключения.

Что-то вроде:

public void method() throws Exception{
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println(e.getMessage());
   }
}

или же

public void method(){
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println("Catching IOException");
           System.out.println(e.getMessage());
   }catch(Exception e){
           System.out.println("Catching any other Exceptions like NullPontException, FileNotFoundExceptioon, etc.");
           System.out.println(e.getMessage());
   }

}

Игнасио Лукатеро
источник
1

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

ДэйвДжонстон
источник
1

Это не ответ, а комментарий, но я не мог написать комментарий с форматированным кодом, поэтому вот комментарий.

Допустим, есть

public static void main(String[] args) {
  try {
    // do nothing or throw a RuntimeException
    throw new RuntimeException("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

На выходе

test
Exception in thread "main" java.lang.RuntimeException: test
    at MyClass.main(MyClass.java:10)

Этот метод не объявляет никаких исключений "бросает", а выбрасывает их! Хитрость в том, что выдаваемые исключения являются исключениями RuntimeExceptions (не отмечены), которые не нужно объявлять в методе. Это немного вводит в заблуждение читателя метода, поскольку все, что он видит, - это «бросок е»; заявление, но без объявления исключения throws

Теперь, если у нас есть

public static void main(String[] args) throws Exception {
  try {
    throw new Exception("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

Мы ДОЛЖНЫ объявлять исключения "throws" в методе, иначе мы получим ошибку компилятора.

Αλέκος
источник
Компилятор выполняет удивительно сложный статический анализ, чтобы решить, throwsтребуется ли.
Брент Брэдберн