- Learning Dart(Second Edition)
- Ivo Balbaert Dzenan Ridjanovic
- 806字
- 2021-07-16 19:47:08
Recognizing and catching errors and exceptions
As a good programmer, you test your app in all possible conditions. Dart defines a number of errors for those things that you should remedy in your code, such as CastError
when a cast fails, or NoSuchMethodError
when the class of the object on which the method is called does not have this method, and neither does any of its parent classes. All these are subclasses of the Error
class, and you should code so that they do not occur. However, when something unexpected occurs while running the app and the code cannot cope with it, Unhandled Exception
occurs. Especially, the input values that are read in from the keyboard, a file, or a network connection are dangerous. Suppose the input is such a value that is supposed to be an integer (refer to exceptions.dart
); we try to convert it into an int
type in line (1)
:
var input = "47B9"; // value read from input, // should be an integer int inp = int.parse(input); (1)
While running the program on the console with the dart exceptions.dart
command, our program will terminate with an exception:
Unhandled exception: FormatException: 47B9 #0 int.parse (dart:core-patch:1586:41) #1 main (file:///E:/dart/code/chapter_2/exceptions/bin/exceptions.dart:4:22)
While running in Dart Editor, the default behavior is that the debugger kicks in so you can examine the exception and the values of all the variables (you can change this behavior by navigating to Tools | Preferences | Run and Debug, and change Break on Exceptions to None). The generated FormatException
is clear: the input was in the wrong format. A lot of the other exceptions exist such as IntegerDivisionByZeroException
, IOException
(failure to read or write a file), and HttpException
(while requesting a page from a web server); they are all subclasses from the Exception
class. When they are generated, they are objects that contain information about the exception. How can we handle this exception so that our program does not crash? For this, Dart follows the familiar try...on/catch...finally
pattern:
try
: To try the dangerous statement(s)on/catch
: To catch the exception (a specific one that you know can occur or a general exception) and stop it from propagatingfinally
: It contains code (perhaps to clean up, or close files or connections) that will be executed whether or not an exception occurs, but it is optional.
A minimal exception handler could be as shown in the following code:
try { int inp = int.parse(input); } on FormatException { print ('ERROR: You must input an integer!'); }
This prints out the text in the on
part. Use catch
if you want to examine the exception object. The last clause in the try
statement should be on Exception catch(e)
or, even better, a simple catch(e)
to stop any type of error or exception. So, the most general exception handler is:
try { int inp = int.parse(input); } on FormatException { // or any other specific exception print ('ERROR: You must input an integer!'); } on Exception catch(e) { // Any other exception print('Unknown exception: $e'); } catch(e) { // No specified type, handles all print('Something really unknown: $e'); } finally { print('OK, I have cleaned up the mess'); }
If you comment out the on FormatException
part, you'll see that $e
contains FormatException: 47B9
.
Should an abnormal condition occur, you can generate or throw an exception in your code with throw
. An example is given in the following code:
var radius = 8; var area = PI * pow(radius, 2); if (area > 200) { // area is 201.06192982974676 throw 'This area is too big for me.'; }
You can also throw a real Exception
object with throw new Exception("…")
. The throw
keyword produces an expression, so it can be used after a =>
operator, like this:
clearBalance() => throw const UnimplementedError();
It is handy to remind yourself while testing that this method hasn't yet been implemented! The bottom line is to test your code exhaustively and provide exception handling for unforeseeable events that your app cannot process in a normal way.
A debugging exercise
The following little program (debuggingex.dart
) results in RangeError
. Use the debugger from the beginning to see where it goes wrong and correct it. In Dart Editor, double-click on a narrow column to the left of for (var i=0; i<=lst.length; i++) {
in order to create a breakpoint (a blue circle). Run the program and use step over to get a new value of the i
variable. Correct the program to avoid the range error. However, don't use try…catch
to handle the error, because it is the programmer's mistake:
// calculate and print the squares of the list items: var lst = [1, 2, 3, 4, 5]; void main() { for (var i=0; i<=lst.length; i++) { print(lst[i] * lst[i]); } }
The following screenshot shows RangeError
in the debugger: