Lab 04: Exceptions
validating input and handling errors gracefully
In this lab, you will learn how to use exceptions to handle unexpected or erroneous input gracefully. For the assignment, you will write a program that parses integer values given by the user as input. That is, given a sequence of characters, your program will either (1) identify the string as representing an integer and store that value as an int
, or (2) identify that the string does not represent an integer, and send an appropriate warning to the user. In case (2), the program should return to a “safe” state and continue to operate as expected despite the “bad” input given by the user.
Note. To get going with the lab, here are some extra resources for exception handling:
- Handling Exceptions (notes)
- Chapter 11, Exceptions in Java Programming
- Oracle tutorial: Exceptions
I recommend writing a version of the program that does catch exceptions first, then modifing your program to handle exceptions. I also suggest working through the Handling Exceptions notes before impelementing the exception handling part of the program.
Here is a sample interaction with the completed program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Enter a number (-1 to exit): 1
x = 1
Enter a number (-1 to exit): 142
x = 142
Enter a number (-1 to exit): -452
x = -452
Enter a number (-1 to exit): 1c34
Could not read integer. InvalidIntegerException: Non-numerical character 'c' encountered.
Enter a number (-1 to exit): 14.3
Could not read integer. InvalidIntegerException: Non-numerical character '.' encountered.
Enter a number (-1 to exit): -34.2
Could not read integer. InvalidIntegerException: Non-numerical character '.' encountered.
Enter a number (-1 to exit): 1 2 3 4 5
x = 1
Enter a number (-1 to exit): x = 2
Enter a number (-1 to exit): x = 3
Enter a number (-1 to exit): x = 4
Enter a number (-1 to exit): x = 5
Enter a number (-1 to exit): -1
x = -1
Goodbye!
In particular, the “expected” inputs (i.e., strings of characters representing integers) are handled as expected. “Unexpected” inputs result in a warning being printed the user, but the program does not crash. Instead, the program returns to a state where it can read the next input from the user.
To get started, download the following files, linked to below:
There are two things you must complete in the code above:
- In
Parser.java
, write the methodint readInt()
. The method should read characters from theInputStream in
(an instance variable for theParser
class). Specifically, your method should read the successive characters fromin
until the next whitespace character or end of stream is encountered (The methodCharacter.isWhitespace(char ch)
will probably be helpful here). If those characters constitute an integer—i.e., are all digits0
through9
, possibly starting with the-
character—thenreadInt()
should return theint
whose decimal representation corresponds to these characters. If a non-numerical character is encountered,readInt()
should do the following.- Continue reading from
in
until the next whitespace character is read or the end of the stream is reached. - Throw an
InvalidIntegerException
with a message indicating the first non-numerical character encountered inin
.
- Continue reading from
- In
ParserTester.java
, modify the main loop so that the program also catches anyInvalidIntegerException
raised inParser
. When anInvalidIntegerException
is caught, the program should print the messageCould not read integer.
to the screen, followed by the details of the caught exception. Note that anInvalidIntegerException
should not break out of the main loop in the program—after anInvalidIntegerException
, the user should be able to continue entering more values.
Notes
The class InputStream
offers only basic operations for reading input. Specifically, you will need to use the read()
method to access each character from in
individually. See the InputStream
documentation for more info. Note that read()
throws an exception, so you must update the declaration of readInt()
to deal with this exception as well as the InvalidIntegerException
you define.
As indicated in the InputStream
documentation, the read()
method returns an int
whose value is -1
if the end of the stream is reached. Otherwise, the returned value is between 0 and 255 (inclusive), and represents the next byte stored in the stream. Each byte represents a single character in the stream. For ASCII text (i.e., the text encoding used for console applications), you can see the correspondence between byte
(or int
) values and their char
equivalents on this page. From the chart, we can see that, for example, casting the character '
W
'
as an int
will store a value of 87.
1
2
int capitalA = (int) 'A'; // stores value 65
int lowerCaseB = (int) 'b'; // stores value 98
Thankfully, you don’t need to know the conversion from char
to int
explicitly to figure out the value of a digit associated to a char. It is enough to know that the characters 0
, 1
, …, 9
appear sequentially in the ASCII code. Thus, we can use the following trick to get an int whose value is the digit stored in a char ch
:
1
int digit = (int) ch - (int) '0';
For example if ch
stores the character 4
, the value of digit
will be 4
after executing the line above. This pattern will be helpful to get the numerical value associated to a digit read from in
. You can also test that ch
represents a digit by checking if (int) 0 <= (int) ch
and (int) ch <= (int) 9
.
A note on style
In order to refer to refer to a fixed char
value, you should always use the literal character in your code rather than its ASCII (integer) value. For example:
1
2
char c = 'A'; // GOOD: refer to the literal char
char d = 65; // BAD: never do this
Requirement
Your program must implement the logic to parse an int
from a sequence of char
s. In particular, you may not use the Integer.parseInt(...)
method, or any similar method that handles the parsing for you.
What to submit
Submit all code needed to run your program (InvalidIntegerException.java
, Parser.java
, ParserTester.java
) to the Moodle site by Friday, March 26th, 11:59 AoE. Additionally, please fill out the survey linked to from the Moodle submission site.
Grading
The lab will be graded on a 3 point scale as follows:
- 3 Everything compiles and runs as specified in this document; code is fairly readable and contains comments briefly describing the main functionality of methods defined/larger chunks of code.
- 2 The program produces more-or-less correct output, but is sloppy/hard to read; comments may be there, but are not helpful.
- 1 Program compiles, but is far from producing the expected output and/or does not run as specified; comments unhelpful or absent.
- 0 Program doesn’t compile or outputs garbage; no comments explaining why.
Additionally, extra credit will be awarded for early submissions (up to 4 days early) as specified in the course syllabus.
Extensions
Write a program that uses the InputStream
and exception handling to validate other types of input. For example, you could write a password validator that reads a stream of characters (ending with whitespace) and determines if the text is a strong password. Here a strong password should:
- be at least 8 characters in length;
- contain at least one capital and one lower-case letter;
- contain at least one numerical character;
- contain at least one “special” character (not a letter or number).