Коли використовувати кидки в оголошенні методу Java?


82

Тож я подумав, що добре розуміюся на обробці винятків у Java, але нещодавно читав якийсь код, який викликав у мене сум'яття та сумніви. Мій головний сумнів, що я хочу звернутися тут, полягає в тому, коли людина повинна використовувати кидки в декларації методу Java, як показано нижче:

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

Читаючи деякі подібні повідомлення я зрозумів , що проливає використовується як свого роду заяву , що 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 і все.

Відповіді:


79

Якщо ви ловите винятковий тип, вам не потрібно його кидати, якщо ви не збираєтеся його повернути. У прикладі, який ви публікуєте, розробник повинен був зробити те чи інше, а не те, і інше.

Як правило, якщо ви не збираєтеся робити нічого за винятком, вам не слід це ловити.

Найнебезпечніше, що ви можете зробити, це зловити виняток і нічого з ним не робити.

Хороша дискусія про те, коли доречно кидати винятки, тут

Коли кидати виняток?


2
Чи повинні непроверені винятки також оголошуватися в підписі методу з допомогою "throws", чи це практика використовувати "throws" лише для перевірених винятків?
Коді

Ця відповідь не стосується безпосередньо центрального аспекту питання: використання 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.


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потрібно це.
Брент Бредберн,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.