необходимость перехвата исключений relax

#java #checked-exceptions

#java #проверено-исключения

Вопрос:

Есть ли в Java возможность избавиться от необходимости перехвата не RuntimeException исключений? Может быть, флаги компилятора?

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

 try {
     connection.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}   
  

что приводит к путанице в 4 строках кода и вводит путаницу переноса RuntimeException при выводе ошибки. Иногда это даже побуждает людей оборачивать большие try ... catch (Throwable ..) блоки вокруг чего угодно, что является вероятной причиной наших любимых предупреждений «Произошла неизвестная ошибка»…

Комментарии:

1. Может быть, создать более значимое непроверенное исключение? Это не так уж плохо, если вы можете инкапсулировать эти четыре строки в один класс или статический метод.

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

3. для исключений при закрытии, когда маловероятно, что вы собираетесь что-либо делать с exception, люди склонны писать closeQuietly метод, аналогичный IOUtils.closeQuietly , но для соединений.

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

Ответ №1:

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

Комментарии:

1. Не будет работать, если метод переопределяет не throws метод, например Thread.run()

Ответ №2:

Сбой приложения при первом появлении исключения является очень плохой практикой. Особенно, когда какая-то работа не сохранена и приложение использует некоторые ресурсы, которые необходимо освободить и очистить, прежде чем приложение завершит выполнение. Для этого использовалось какое-то очень популярное программное обеспечение … и вместо «исправления» проблемы они внедрили функции восстановления данных при перезапуске приложения. Однако фокус в том, что это не очень хорошая разработка программного обеспечения.

По крайней мере, ваше приложение не должно аварийно завершать работу при первом обнаруженном исключении / ошибке, а восстанавливаться с помощью значимого сообщения. Лениво просто оборачивать все в RuntimeException (или даже Throwable ) и, особенно, ничего с этим не делать.

Java не поддерживает флаги любого вида, потому что есть 1) обходной путь и 2) лучшие способы справиться с этой ситуацией. Например :

1. Обработайте исключение в вызывающем методе

Вы можете добавить throws ключевое слово в объявление вашего метода, вплоть до вашего static public void main метода, который, если не обрабатывает исключение, в конечном итоге приведет к аварийному завершению работы приложения с помощью stacktrace.

 class Foo {
   public void someMethod(....) throws IllegalArgumentException, IOException {
      ...
   }

   static public void main(String...args) throws Throwable {
      new Foo().someMethod();
   } 
}
  

Этот метод не предлагает никаких средств восстановления и, вероятно, сделает вашего пользователя несчастным (с большим бессмысленным отслеживанием статистики, если они запустили приложение с консоли, или вообще ничего, если они запустили его с помощью ярлыка или графического интерфейса пользователя). Кроме того, если у вас есть некоторые приобретенные ресурсы, вы не сможете очистить их при возникновении исключения. По крайней мере, вы main должны catch (Throwable e) что-то вывести, прежде чем создавать исключение выше. Что-то вроде :

 class Foo {
   public void someMethod(....) throws IllegalArgumentException, IOException {
      ...
   }

   static public void main(String...args) {
      try {
         new Foo().someMethod();
      } catch (...) {
         // output or log exception here and, optionally, cleanup and exit
      }
   } 
}
  

** РЕДАКТИРОВАТЬ **

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

 public E doSomething() throws RuntimeException {
   // declare a bunch of resources

   try {
      // process resources with unchecked exceptions
   } finally {
      // free resources
   }

   // return some result
}
  

и аккуратно завершите метод при ошибке или успешном завершении, возможно, даже зарегистрировав ошибку времени выполнения для «потомства».

2. Зарегистрируйте ошибку и верните некоторое значимое значение

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

 class Foo {
   static private final Logger LOG = Logger.getLogger(Foo.class.getName());

   public boolean doSomethingImpl(...) {
      boolean result = true;
      try {
        ...
      } catch (SomeException e) {
         LOG.log(Level.SEVERE, "meaningful message why method could not do something!", e);
         result = false;
      }
      return resu<
   }

   public void doSomething() {
      if (!doSomethingImpl(...)) {
          // handle failure here
      }
   }
}
  

По умолчанию Logger все будет выводиться в err выходной поток, но вы можете добавить свои собственные обработчики :

 // loggers are singletons, so you can retrieve any logger at anytime from
// anywhere, as long as you know the logger's name
Logger logger = Logger.getLogger(Foo.class.getName());

logger.setUseParentHandlers(false);  // disable output to err
logger.addHandler(new MyHandler());  // MyHandler extends java.util.logging.Handler
  

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

и т.д.

Комментарии:

1. «Сбой приложения при первом же появлении исключения — это очень плохая практика. Особенно, когда какая-то работа не спасена «. Хорошо. Но при написании небольших командных приложений или плагиноподобных исполняемых файлов нет необходимости терять работу, и каждая ненужная строка кода или искаженный отладочный вывод для меня плохая практика. Вывод ошибки исключения java с указанием его кодовой позиции меня устраивает. Некоторые другие надежные инструменты работают подобным образом, например rsync , которые регистрируют файл кода и номер строки при сбое.

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

3. Ну, я наткнулся на этот вопрос на пути к хорошему коду… Я предпочитаю минималистичный, небольшой код, и поэтому мне не нравится предопределенное применение проверки Java к некоторым Exception s.

4. @dronus, тогда я полагаю, что вы не до конца понимаете смысл наличия исключений; Java имеет исключения по уважительным причинам. Среди одного из них An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions. Исключения позволяют переходить к различным возможным событиям; в отличие от простого возврата null (или 0) или полагаться на вызов другого метода, чтобы выяснить, что / почему / где. Я предлагаю вам прочитать весь раздел, более конкретно download.oracle.com/javase/tutorial/essential/exceptions /…

5. Ну, именно этого я и хочу. При возникновении какой-либо проблемы нормальный поток инструкций программы должен быть нарушен, и в моем случае программа должна немедленно завершиться, описав проблему stderr . Но Java заставляет меня перехватывать НЕКОТОРЫЕ исключения и выполнять специальную обработку самостоятельно. Поэтому, если я решу выйти из программы и на этих, мне придется написать дополнительный код повторного ввода, и результирующий stderr вывод обычно отличается от не перехваченного RuntimeException . Вот и весь факт, который мне не нравится, и от которого я хотел избавиться, что, как кажется, невозможно.

Ответ №3:

Есть ли в Java возможность избавиться от необходимости перехвата исключений, отличных от RuntimeException?

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

Может быть, флаги компилятора?

Нет. Для этого нет флагов компилятора. Это фундаментальная часть языкового дизайна. Ослабление правил исключения checked с помощью переключателя компилятора вызвало бы серьезные проблемы с совместимостью библиотек.

Ответ №4:

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

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

Комментарии:

1. «Лучше всего, чтобы ваши методы повторно создавали исключение» часто невозможно, если переопределяется метод framework. Например, Thread.run() метод не позволяет отбрасывать исключения.

Ответ №5:

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

 public class Foo {
    public Foo() {
        super();
    }
    public void disconnect(connection) throws IOException {
        connection.close();
    }
}
  

Комментарии:

1. Это невозможно, если переопределять методы фреймворка, такие как Thread.run()

2. Ах, спасибо, я не знал об этом. В прошлом я действительно не сталкивался с управлением потоками.

Ответ №6:

Используйте «Throws», чтобы избежать ошибки .. но это не будет хорошей практикой программирования