Spec-Zone .ru
спецификации, руководства, описания, API
|
Теперь, когда Вы знаете то, что исключения и как использовать их, пора изучить преимущества использования исключений в Ваших программах.
Исключения обеспечивают средства разделить детали того, что сделать, когда что-то необычное происходит от основной логики программы. В традиционном программировании обнаружение ошибок, создание отчетов, и обработка часто приводят к запутывающему запутанному коду. Например, рассмотрите метод псевдокода здесь, который читает весь файл в память.
readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; }
На первый взгляд эта функция кажется достаточно простой, но она игнорирует все следующие потенциальные ошибки.
Обработать такие случаи, readFile
у функции должно быть больше кода, чтобы сделать обнаружение ошибок, создание отчетов, и обработку. Вот пример того, на что могла бы быть похожей функция.
errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode; }
Есть так много обнаружения ошибок, создания отчетов, и возврата здесь, что исходные семь строк кода теряются в помехе. Хуже все же, логический поток кода был также потерян, таким образом мешая говорить, делает ли код правильную вещь: файл действительно закрывает, если функция не в состоянии выделить достаточно памяти? Еще более трудно гарантировать, что код продолжает делать правильную вещь, когда Вы изменяете метод спустя три месяца после записи этого. Много программистов решают эту проблему, просто игнорируя это — об ошибках сообщают, когда их программы отказывают.
Исключения позволяют Вам записать основной поток своего кода и иметь дело с исключительными случаями в другом месте. Если readFile
функционируйте используемые исключения вместо традиционных методов управления обработкой ошибок, это больше походило бы на следующий.
readFile { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } }
Отметьте, что исключения не экономят Вас усилие по выполнению работы обнаружения, создания отчетов, и ошибок из-за неправильного обращения, но они действительно помогают Вам организовать работу эффективнее.
Второе преимущество исключений является возможностью распространить сообщение об ошибке стек вызовов методов. Предположите что readFile
метод является четвертым методом в серии вложенных вызовов метода, сделанных основной программой: method1
вызовы method2
, который вызывает method3
, который наконец вызывает readFile
.
method1 { call method2; } method2 { call method3; } method3 { call readFile; }
Предположите также это method1
единственный метод, заинтересованный ошибками, которые могли бы произойти в пределах readFile
. Традиционная сила методов уведомления об ошибке method2
и method3
распространить коды ошибки, возвращенные readFile
стек вызовов до кодов ошибки наконец достигает method1
— единственный метод, который интересуется ими.
method1 { errorCodeType error; error = call method2; if (error) doErrorProcessing; else proceed; } errorCodeType method2 { errorCodeType error; error = call method3; if (error) return error; else proceed; } errorCodeType method3 { errorCodeType error; error = call readFile; if (error) return error; else proceed; }
Вспомните, что среда выполнения Java ищет назад через стек вызовов, чтобы найти любые методы, которые интересуются обработкой определенного исключения. Метод может наклонить любые исключения, выданные в пределах этого, таким образом позволяя метод дальше стек вызовов поймать это. Следовательно, только методы, которые заботятся об ошибках, должны волноваться об обнаружении ошибок.
method1 { try { call method2; } catch (exception e) { doErrorProcessing; } } method2 throws exception { call method3; } method3 throws exception { call readFile; }
Однако, поскольку псевдокод показывает, наклоняя исключение, требует некоторого усилия со стороны методов посредника. Любые проверенные исключения, которые могут быть выданы в пределах метода, должны быть определены в throws
пункт.
Поскольку все исключения, выданные в пределах программы, являются объектами, группировка или категоризация исключений являются естественным результатом иерархии class. Пример группы связанных классов исключений в платформе Java - определенные в java.io
— IOException
и его потомки. IOException
является самым общим и представляет любой тип ошибки, которая может произойти, выполняя ввод-вывод. Его потомки представляют более определенные ошибки. Например, FileNotFoundException
средства, что файл не мог быть расположен на диске.
Метод может записать определенные обработчики, которые могут обработать очень определенное исключение. FileNotFoundException
У class нет никаких потомков, таким образом, следующий обработчик может обработать только один тип исключения.
catch (FileNotFoundException e) { ... }
Метод может поймать исключение, основанное на его группе или общем типе, определяя любой из суперклассов исключения в catch
оператор. Например, чтобы поймать все исключения ввода-вывода, независимо от их определенного типа, обработчик исключений определяет IOException
параметр.
catch (IOException e) { ... }
Этот обработчик будет в состоянии поймать все исключения ввода-вывода, включая FileNotFoundException
, EOFException
, и так далее. Можно найти детали о том, что произошло, запрашивая параметр, который передают к обработчику исключений. Например, используйте следующий, чтобы напечатать трассировку стека.
catch (IOException e) { // Output goes to System.err. e.printStackTrace(); // Send trace to stdout. e.printStackTrace(System.out); }
Вы могли даже установить обработчик исключений, который обрабатывает любого Exception
с обработчиком здесь.
// A (too) general exception handler catch (Exception e) { ... }
Exception
class близко к вершине Throwable
Иерархия class. Поэтому, этот обработчик поймает много других исключений в дополнение к тем, которых обработчик предназначается, чтобы поймать. Можно хотеть обработать исключения этот путь, если все, что Вы хотите, чтобы Ваша программа сделала, например, распечатывают сообщение об ошибке для пользователя и затем выходят.
В большинстве ситуаций, однако, Вы хотите, чтобы обработчики исключений были настолько определенными насколько возможно. Причина состоит в том, что первая вещь, которую должен сделать обработчик, определяют, какое исключение произошло прежде, чем это сможет выбрать лучшую стратегию восстановления. В действительности, не фиксируя определенные ошибки, обработчик должен разместить любую возможность. Обработчики исключений, которые являются слишком общими, могут сделать код более подверженным ошибкам, ловя и обрабатывая исключения, которые не ожидались программистом и для которого не был предназначен обработчик.
Как отмечено, можно создать группы исключений и обработать исключения общим способом, или можно использовать определенный тип исключения, чтобы дифференцировать исключения и исключения дескриптора точным способом.