2009-02-10 3 views
4

В Java есть определенные предопределенные исключения, которые, если их бросить, сообщают, что произошло что-то серьезное, и вам лучше улучшить свой код, чем поймать их в блоке catch (если я правильно понял) , Но все-таки я нахожу много программ, в которых у меня есть следующие:Ловля исключений в Java

} catch (IOException e) { 
    ... 
} catch (FileNotFoundException e) { 
    .... 
} 

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

Спасибо.

ответ

14

Нет, нет ничего плохого в ловле IOException и FileNotFoundException - если вы можете действительно ручки эти исключения. Это важный бит - можете ли вы действительно действовать перед лицом этого исключения? Иногда вы можете - очень часто - на верхнем уровне сервера, например, когда только потому, что один запрос терпит неудачу, не означает, что следующий не может продолжаться. Реже в клиентских приложениях, хотя это сильно зависит от ситуации. Не можете прочитать файл, когда вы пытаетесь импортировать пакет? Хорошо, прервите операцию, но не обязательно выключите весь процесс ...

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

3

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

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

5

Порядок, который вы показываете, с IOException уловлен до FileNotFoundException. Так как FileNotFoundException расширяет IOException, когда выбрано FileNotFoundException, первый обработчик будет использоваться, а второй обработчик - мертвый код.

Я не пробовал, но я немного удивлен, если это скомпилируется. Надеюсь, инструмент статического анализа, такой как FindBugs, поймает эту ошибку.

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

+0

Очень хороший момент, и хороший ответ. – hotshot309

4

Существует два типа исключений в Java, проверенные исключения и исключенные исключения.

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

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

Для записи IOException может быть выбрано для чего-то столь же простого, как попытка открыть файл, который не существует. Рекомендуется обработать что-то вроде этого и изящно восстановить (диалог с пользователем о том, что файл не существует и снова открывается диалоговое окно с открытым файлом или что-то в этом роде), а не сбой программы.

3

Jon says В большинстве случаев улавливание этих исключений является прекрасным. Вид исключений, которые вы не должны ловить, такие вещи, как NullPointerException и ArrayIndexOutOfBoundsException, указывают на ошибки в вашем коде.

Java имеет два типа исключений: проверенные исключения и непроверенные исключения (те, которые наследуются от RuntimeException).

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

Исключенные исключения, с другой стороны, лучше всего использовать для вещей, которых можно избежать, изменив код. Исключение NullPointerException всегда можно избежать, если код делает проверку на возможность нулевой ссылки. Аналогично, если вы будете осторожны с вашими индексами, вы никогда не получите исключение ArrayIndexOutOfBoundsException. Компилятор не обязывает вас обрабатывать эти сценарии, поскольку они представляют собой ошибки, которые должны быть исправлены.

3

Я думал, что IOException и FileNotFoundException точно такого рода исключений

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

Подумайте об этом сценарии:

Вы создаете приложение, которое сохраняет данные в папку темп.

Все в порядке, вы проверили, существует ли папка, а если нет, вы создаете ее самостоятельно.

А затем вы пишете 2 мб в эту временную папку.

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

Нет ничего, что можно было бы сделать, чтобы предотвратить это программно, в некоторых системах, которые могут произойти (в unix пользователь root может выполнять rm -rf/tmp, и вы ничего не можете с этим поделать. система не позволит другому процессу удалить файл, который используется)

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

Jon is correct иногда нет ничего, что вы можете сделать об этом, вероятно, ведение журнала, прежде чем умирает программа, которая рассматривается как «обработать исключение» (бедные ручки да, но обращаться по крайней мере)

try { 
    .... 
} catch(IOException ioe) { 
    logger.severe( 
     String.format("Got ioe while writting file %s. Data was acquired using id = %d, the message is: %s", 
      fileName, 
      idWhereDataCame, 
      ioe.getMessage())); 
    throw ioe; 
} 

Другое дело вы можете сделать это, чтобы «объединить» исключение, чтобы соответствовать абстракции.

Возможно, ваше приложение имеет графический интерфейс, отображающий IOException для пользователя, не будет означать ничего или может быть security vulnerability. Модифицированное сообщение может быть отправлено.

try { 
    .... 
} catch(IOException ioe) { 
    throw new EndUserException("The operation you've requeste could not be completed, please contact your administrator" , ioe); 
}  

И EndUserException может оказаться в ловушке где-то в графическом интерфейсе и представлена ​​пользователю в диалоговом окне (вместо того, чтобы просто исчезнуть приложение в его глазах без дополнительной информации). Конечно, вы ничего не смогли сделать, чтобы восстановить это IOException, но по крайней мере вы умираете со стилем: P

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

Например, подумайте еще раз о первом сценарии. Эта же «операция» может иметь три вида «плагинов» для выполнения сохранения данных.

a) Write the data to a file. 
b) Or, write to a db 
c) Or write to a remote server. 

Интерфейс не должен бросать:

java.io.IOException 
java.sql.SQLException 

ни

java.net.UnknownHostException 

Но вместо того, что-то вроде

my.application.DataNotSavedException 

и различных реализаций будет обрабатывать исключение при правильной L Evel, и преобразовать его в соответствующий абстракции:

код клиента: код

DataSaver saver = DataServer.getSaverFor("someKeyIdString"); 

try { 
    saver.save(myData); 
} catch(DataNotSavedException dnse) { 

    // Oh well... . 
    ShowEndUserError("Data could not be saved due to : " dnse.getMessage()); 
} 

осуществления:

class ServerSaver implements DataSaver { 
.... 
    public void save(Data data) throws DataNotSavedException { 
     // Connect the remore server. 
     try { 
      Socket socket = new Socket(this.remoteServer, this.remotePort); 
      OuputStream out = socket.getOut.... 

      .... 
      .... 
     } catch (UnknownHostException uhe) { 
      // Oops.... 
      throw new DataNotSavedException(uhe); 
     } 
    } 
} 

FileSaver и DatabaseSaver бы сделать что-то подобное.

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

Когда использовать один или другой (проверено/снят): here

Есть два других вида: here

И, наконец, гораздо проще объяснение среды выполнения: here

0

Взять эту идею немного: может быть, в другом домене яснее

Что вы будете делать, если автомобиль в fr ты внезапно останавливаешься.

Остановитесь!

Таким образом, мы обрабатываем исключение.

Итак, вернусь к коду:

Что делать, если файл вам нужно, это не доступно?

либо

  1. иметь резервную копию. Составлено в качестве ресурса , потому что это часть вашей программы . Я не шучу.
  2. IFF ​​Это файл, предоставленный пользователем: Сообщите пользователю; это их файл.
  3. Прервать программу с сообщением пользователю, потому что ваше программное обеспечение SYSTEM сломанно.

Я считаю, что нет четвертого варианта.

Наши братья C#/VC++ выбирают непроверенные исключения. Многие «эксперты» считают, что проверенные исключения плохи: я утверждаю, что жизнь сложная, преодолевай ее. Проверяемые исключения представляют собой известные режимы отказа: их необходимо устранить. Диаграмма вашей рыбы имеет прямую ложь для нормальной работы и разветвляется сбоку для сбоев. Проверенными исключениями являются ожидаемые сбои.

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

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