CS 1713 Week 7:
Exceptions and File I/O

Objectives:

Activities:

Readings: 11.1 - 11.6, 9.7 - 9.8

Terminology:


Exceptions:

An Exception is an object that defines an unusual or erroneous situation.

Example 1: The following code generates an ArithmeticException.

   int num = 10;
   int den = 0;
   int fraction = num/den;
   System.out.println(fraction);

Example 2: The following code avoids the error by using a guard:
   
   int num = 10;
   int den = 0;
   int fraction;
   if (den == 0) {
      System.out.println("Divide by zero, setting fraction to 0");
      fraction = 0;
   }else
      fraction = num/den;
   System.out.println("Fraction is " + fraction);

Example 3: The following code handles the divide-by-zero error by catching the resulting exception.

   
   int num = 10;
   int den = 0;
   int fraction = 0;
   try {
       fraction = num/den;
   } catch(ArithmeticException e) {
       System.err.println("Divide by zero, setting fraction to 0");
       fraction = 0;
   } finally {
       System.out.println("Fraction is " + fraction);
   }

Exercise 1: What type of Exception does Example 3 generate?
Ans: An ArithmeticException is generated and caught.

Exercise 2: What output is produced by Example 3?
Ans:
   Divide by zero, setting fraction to 0
   Fraction is 0
Note: The first message is written to standard error which is a different device than standard output. When running in eclipse, both of these devices are directed to the message window, but the standard error messages are displayed in red. The messages may come out in different order.

Exercise 3: Why does fraction of Example 3 have to be declared outside of the try-catch-finally?
Ans: If fraction is declared in the try block it will not be accessible in the catch or the finally blocks. If fraction is declared in the catch or finally blocks, a similar problem occurs.

Exception hierarchy:

Exercise 4: What catch clauses would catch the exception thrown by Exercise 1?
Ans: A catch clause containing any Throwable above it in the class hierarchy: Note: Although any of these catch clauses would work, you generally want to be as specific as possible. The more general clauses (higher in the class hierarchy) do not allow you to distinguish between different types of exceptions.

Example 4: Sometimes it is useful convert a String to a numeric value so that you can use it in calculations. The static method parseInt in the Integer class can be used to accomplish this:
   String s = "12345";
   int n;
   n = Integer.parseInt(s);
If the String cannot be converted because it contains invalid characters, a NumberFormatException is thrown. We can handle this as follows:
   String s = "12345a";
   int n;
   try {
      n = Integer.parseInt(s);
   } catch (NumberFormatException e) {
      System.out.println("Handle an error here");
   }

Floating point values can be converted in a similar way:

   String s = "123.456";
   double x;
   try {
      x = Double.parseDouble(s);
   } catch (NumberFormatException e) {
      System.out.println("Handle an error here");
   }

I/O and exceptions

A byte stream is a sequence of bytes. We have been using three streams since the beginning. System.in is the standard input stream, System.out is the standard output stream, and System.err is the standard error stream.

We have used the Scanner class for input using the input stream System.in.

Exercise 5: What does the following do if you enter abc instead of an integer?

   Scanner scan = new Scanner(System.in);
   System.out.println("Enter an integer:");
   int count = scan.nextInt();
Ans: It throws an InputMismatchException.

Exercise 6: How can you fix the code in exercise 5 to handle the exception?

Ans There are many ways of doing this. One way is to prompt again if the input is invalid:

   Scanner scan = new Scanner(System.in);
   int count;
   boolean validInput;
   validInput = false;
   System.out.println("Enter an integer:"); 
   while (!validInput) {
      try {
         count = scan.nextInt();
         validInput = true;
      } catch (InputMismatchException e) {
         scan.next();                             // remove the bad token
         System.out.println("Invalid input, enter an integer:");
      }
   }

File Input

The parameter to the constructor of the Scanner class that we have used is an InputStream. We can create an input stream corresponding to disk file as follows:

   InputStream ins = new FileInputStream("myfile");
Alternatively, we can create the input stream when we create the scanner:
   Scanner scan = new Scanner(new FileInputStream("myfile"));
Exceptions play a very important role in the handling of I/O. You cannot create an input stream from a file that does not exist or one that you do not have permission to read from.
In this case a FileNotFoundException can be thrown.
The Java documentation also states that this can throw a SecurityException. (This can happen, for example if you try to read a file on the local disk from an applet run inside a browser.)

File Output

There are many ways of creating output files. We will look at just one of these. We already know how to output to the screen with System.out.println.

System.out is an example of a PrintWriter. Every PrintWriter has print and println methods (among others). We can create a PrintWriter that corresponds to a new file as follows:

   PrintWriter out;
   String filename = "myoutput.txt";

   try {
      out = new PrintWriter(new PrintWriter(filename),true);
   } catch (FileNotFoundException e) {
      System.out.println("This is where we handle an error creating the file");
   }
When we are done writing to the file it is a good idea to close it:
   out.close();
Exercise 7: What happens if you the file myoutput.txt already exists when the above code is executed?

Ans: The old file contents are lost and replaced by the new contents.

In the above example, it looks like we are creating two PrintWriter objects instead of one. We could have just done:

   out = new PrintWriter(filename);
but by default, a PrintWriter does not immediately send the result to the file. It gathers up the output until it has enough to efficiently send to the file, or until a close or flush is executed. The method we are using sets the PrintWriter to autoflush mode which immediately sends everything to the file.

As you might guess, there are lots of details we are not covering here, but the simple methods illustrated allow you to easily create a file.

Choosing a File Interactively

You may want the user to choose a file interactively, rather than hard coding the name of the file into your program. The simplest way to do this is with a JFileChooser. Here are the steps needed to use this.

Example 5 Use a file chooser to select a file for reading:
   JFileChooser chooser = new JFileChooser(".");
   chooser.setDialogTitle("Choose a file");
   int returnValue = chooser.showOpenDialog(window);
   if (returnValue == JFileChooser.APPROVE_OPTION) {
      File file = chooser.getSelectedFile();
      String filename = file.toString();
      System.out.println("File is "+filename);
   }
The (optional) parameter to the constructor is the path that the chooser starts in. In the example, it is the current directory of the project.

The parameter of showOpenDialog is required. This can be the main frame of your program or a button. It can also be null.
To find a file for saving, use showSaveDialog.

The setDialogTitle is optional.

The JFileChooser has a number of other options that you can read about in the documentation.

Graphics Case Study 4: Saving and Restoring Graphical Information

Start with Graphics Case Study 3, change it to gcs04 and change the package to files. Make sure it still runs.

Add two additional buttons called Save and Restore.

When the Save button is pushed, prompt the user for the name of a file (use JFileChooser) and save the current list of shapes in that file. When the Restore button is pushed, prompt the user for the name of a file and set the current list of shapes from the information in the file. Replace any shapes that were previously on the screen.

Store information about a shape on a single line.

Colors will be stored as three integers in the range 0 through 255 giving the red, green, and blue values of the color. Get these from a color using the Color methods: getRed(), getGreen(), and getBlue(). You can create a color from these three numbers by using the constructor:
new Color(int red, int green, int blue);

Write the following methods:
private String getShapeDescriptor(DrawableShape shape);
private DrawableShape decodeShapeDescriptor(String s);
The first creates a string from a shape and the second creates a shape from the corresponding string. The second one should return null if the string is not valid.

Implement these by having the relevant object do most of the work. For example, in DrawableRectangle, write:
public String getDescriptor()
public static DrawableRectangle decodeDescriptor(String s)


Revision Date Sun Nov 27 2005 06:39:30 GMT-0600 (CST)