В процессе работы прогаммы могут возникать различные ошибки, которые нарушают привычный ход программы и даже заставляют ее прервать выполнение. Такие ошибки называются исключениями. Язык Dart, как и многие языки программирования, поддерживает обработку исключений, что позволяет нам избежать аварийного прерывания работы программы.
Рассмотим простейшую ситуацию:
void main (){ int x = 9; int y = 0; int z = x ~/ y; print(z); }
В данном случае происходит целочисленное деление (операция ~/) на 0. В итоге на программа сгенерирует исключение и завершит свое выполнение. Ситуация может показаться искуственной, так как здесь мы очевидно видим, что одна из переменных равна 0, и естественно программа завершится с ошибкой.
c:\dart>dart main.dart Unhandled exception: IntegerDivisionByZeroException #0 int.~/ (dart:core-patch/integers.dart:30:7) #1 main (file:///c:/dart/main.dart:5:16) #2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19) #3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26) c:\dart>
Однако в реальности мы можем получать данные из внешнего источника и точно не знать, какое там значение 0 или не 0. Кроме того, делением на ноль исключения в Dart не ограничиваются, есть много ситуаций, где возможна подобная аварийная остановка работа программы.
Что нам предлагает Dart для обработки подобных ситуаций? Прежде всего это конструкция try...on...catch...finally:
try{ // Код, который может привести к генерации исключения } on Тип_Исключения{ // Обработка возникшего исключения } catch (e){ // Обработка возникшего исключения } finally{ // }
При использовании блока try..on..catch..finally вначале выполняются все инструкции в блоке try.
Если в этом блоке не возникло исключений, то после его выполнения начинает выполняться блок finally. И затем конструкция
try..on..catch..finally
завершает свою работу.
Если же в блоке try вдруг возникает исключение, то обычный порядок выполнения останавливается, то выполнение программы переходит к блоку on или catch, который может обработать возникшее исключение. Если нужный блок on или блок catch найден, то он выполняется, и после его завершения выполняется блок finally.
Разница между операторами on и catch состоит в том, что on обрабатывает исключение определенного типа (подробнее оператор on рассматривается в следующей теме). А catch обрабатывает все исключения.
Если нужный блок on или блок catch не найден, то при возникновении исключения опять же выполняется блок finally, а затем программа аварийно завершает свое выполнение.
Применим конструкцию try..on..catch..finally для обработки деления на 0:
void main (){ try{ int x = 9; int y = 0; int z = x ~/ y; print(z); } catch(e){ print("Возникло исключение $e"); } print("Завершение программы"); }
Здесь код, который может сгенерировать исключение, помещен в блок try. Блок catch в скобках содержит список параметров, которые передаются при
генерации исключении. В данном случае это один параметр - (e)
, который представляет информацию об исключении.
И при выполнении данной программы мы получим следующий консольный вывод:
Возникло исключение IntegerDivisionByZeroException Завершение программы
Здесь мы видим, что несмотря на генерацию исключение, программа не завершилась аварийно, а после выполнения блока catch продолжила свою работу.
При определении конструкции мы можем опускать ряд блоков, если они не нужны. Только блок try является обязательным. Однако вместе с ним должен также использоваться, как минимум, либо блок on и(или) catch, либо блок finally. Так, в примере выше использовались только блоки try и catch. Добавим блок finally:
void main (){ try{ int x = 9; int y = 0; int z = x ~/ y; print(z); } catch(e){ print("Возникло исключение $e"); } finally{ print("Выполнение блока finally"); } print("Завершение программы"); }
Консольный вывод:
Возникло исключение IntegerDivisionByZeroException Выполнение блока finally Завершение программы
В данном случае мы можем опустить блок catch:
void main (){ try{ int x = 9; int y = 0; int z = x ~/ y; print(z); } finally{ print("Выполнение блока finally"); } print("Завершение программы"); // эта строка не выполняется }
После генерации исключения в блоке try выполняется блок finally, после чего программа аварийно останавливает свою работу. Консольный вывод:
Выполнение блока finally Unhandled exception: IntegerDivisionByZeroException #0 int.~/ (dart:core-patch/integers.dart:30:7) #1 main (file:///c:/dart/main.dart:6:13) #2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19) #3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
В блок catch передается ряд параметров, которые несут информацию об исключении и мы можем при необходимости получить и использовать эту информацию:
void main (){ try{ int x = 9; int y = 0; int z = x ~/ y; print(z); } catch(e, s){ print("Обработка исключения $e"); print("Стек $s"); } print("Завершение программы"); }
Первый параметр блока catch - e представляет объект исключения, а второй - s - стек исключений, который позволяет понять, где произошло исключение. Консольный вывод в данном случае:
Обработка исключения IntegerDivisionByZeroException Стек #0 int.~/ (dart:core-patch/integers.dart:30:7) #1 main (file:///c:/dart/main.dart:6:12) #2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19) #3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26) Завершение программы
Так, по консольному выводу можно увидеть, что проблема в 6 строке файла c:/dart/main.dart, где сообственно и возикло исключение.