Exception Handling Chapter 15 Horstmann

An "exception" is a problem that occurs during program execution. Examples we have encountered include ArrayIndexOutOfBoundsException (trying to access an element past the end of an array) and NullPointerException (attempting to use an object that is null, or not yet constructed). These are "unchecked" exceptions in Java: they are your fault, and the compiler will not detect and complain about them.

"Checked" exceptions happen at times no matter how careful you are - for example, in opening a file, a user may enter the name of a nonexistent file. This is so common that Java insists you "handle" this type of error. Competent exception handling should result in robust programs that do not (necessarily) terminate when an error occurs.

Some methods we will encounter (for example, the constructor for a FileWriter object) throw a checked exception (in this case, an IOException if the file cannot be created). The programmer can simply state that the method throws an exception and let the calling method handle things (or the program fail). It is better to enclose such methods in try and catch blocks if the programmer can deal with the error when it occurs (for example, by asking for a new file name).

To illustrate this, we will handle an unchecked, but easily understood, exception. Our first example (from Deitel) is a program that does not handle divide by zero errors or mismatched input. The code and output are below.

// An application that attempts to divide by zero.

import java.util.Scanner;

public class DivideByZeroNoExceptionHandling

{

// demonstrates throwing an exception when a divide-by-zero occurs

public static int quotient( int numerator, int denominator )

{

return numerator / denominator; // possible division by zero

} // end method quotient

public static void main( String args[] )

{

Scanner scanner = new Scanner( System.in ); // scanner for input

System.out.print( "Please enter an integer numerator: " );

int numerator = scanner.nextInt();

System.out.print( "Please enter an integer denominator: " );

int denominator = scanner.nextInt();

int result = quotient( numerator, denominator );

System.out.printf(

"\nResult: %d / %d = %d\n", numerator, denominator, result );

} // end main

} // end class DivideByZeroNoExceptionHandling

Output:

Please enter an integer numerator:

100

Please enter an integer denominator:

7

Result: 100 / 7 = 14

Please enter an integer numerator:

100

Please enter an integer denominator:

0

Exception in thread "main" java.lang.ArithmeticException: / by zero

at NoExceptionHandling.DivideByZeroNoExceptionHandling.quotient (DivideByZeroNoExceptionHandling.java:14)

at NoExceptionHandling.DivideByZeroNoExceptionHandling.main (DivideByZeroNoExceptionHandling.java:26)

Java Result: 1

Please enter an integer numerator:

100

Please enter an integer denominator:

hello

Exception in thread "main" java.util.InputMismatchException

at java.util.Scanner.throwFor(Scanner.java:819)

at java.util.Scanner.next(Scanner.java:1431)

at java.util.Scanner.nextInt(Scanner.java:2040)

at java.util.Scanner.nextInt(Scanner.java:2000)

at NoExceptionHandling.DivideByZeroNoExceptionHandling.main (DivideByZeroNoExceptionHandling.java:24)

Java Result: 1

Next we modify the program to handle the above problems. The modified code and output are below.

// Deitel: DivideByZeroWithExceptionHandling.java

// An exception-handling example that checks for divide-by-zero.

package ExceptionHandling;

import java.util.InputMismatchException;

import java.util.Scanner;

public class DivideByZeroWithExceptionHandling

{

// demonstrates throwing an exception when a divide-by-zero occurs

public static int quotient( int numerator, int denominator )

throws ArithmeticException

{

return numerator / denominator; // possible division by zero

} // end method quotient

public static void main( String args[] )

{

Scanner scanner = new Scanner( System.in ); // scanner for input

boolean continueLoop = true; // determines if more input is needed

do

{

try // read two numbers and calculate quotient

{

System.out.println( "Please enter an integer numerator: " );

int numerator = scanner.nextInt();

System.out.println( "Please enter an integer denominator: " );

int denominator = scanner.nextInt();

int result = quotient( numerator, denominator );

System.out.printf( "\nResult: %d / %d = %d\n", numerator,

denominator, result );

continueLoop = false; // input successful; end looping

} // end try

catch ( InputMismatchException inputMismatchException )

{

System.err.printf( "\nException: %s\n",

inputMismatchException );

scanner.nextLine(); // discard input so user can try again

System.out.println(

"You must enter integers. Please try again.\n" );

} // end catch

catch ( ArithmeticException arithmeticException )

{

System.err.printf( "\nException: %s\n", arithmeticException );

System.out.println(

"Zero is an invalid denominator. Please try again.\n" );

} // end catch

} while ( continueLoop ); // end do...while

} // end main

} // end class DivideByZeroWithExceptionHandling

Output:

Please enter an integer numerator:

100

Please enter an integer denominator:

0

Zero is an invalid denominator. Please try again.

Exception: java.lang.ArithmeticException: / by zero

Please enter an integer numerator:

100

Please enter an integer denominator:

7

Result: 100 / 7 = 14

Please enter an integer numerator:

100

Please enter an integer denominator:

hello

Exception: java.util.InputMismatchException

You must enter integers. Please try again.

Please enter an integer numerator:

100

Please enter an integer denominator:

7

Result: 100 / 7 = 14

InputMismatchException class had to be imported, but ArithmeticException class is part of java.lang class. Note when an exception occurs, the remaining code in the try block will not execute.

Methods such as quotient should have Javadoc style comments that indicate pre and post conditions: what must be true for numerator and denominator parameters and what wil be the results of the method. See below for a template for this comment style.

/** Descriptive phrase. Longer statement of purpose.

<BR<B>Precondition:</B> Precondition goes here

<BR<B>Postcondition:</B> Postcondition goes here

@param p1 A description of this parameter

@param p2 A description of this parameter

@ return A description of the return value

*/

public int someMethod(double p1, String p2)

{

return 0;

}


Files and Streams Chapter 16 Horstmann

Java was developed to control set-top cable boxes. Data was to be received and transmitted byte by byte. Subsequent use of the language for more general purposes resulted in development of layer upon layer of file handling classes. Below, we will:

·  Write, read, and modify text or character based sequential access files.

·  Write and read objects to disk.

·  Use the GUI FileChooser dialog.

// LineNumberer (modified): Chapter 16 Horstmann

package LineNumberer;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Scanner;

public class LineNumberer

{

public static void main(String[] args)

{

Scanner console = new Scanner(System.in);

System.out.println("Input file: "); // note println

String inputFileName = console.nextLine(); // allows spaces

System.out.println("Output file: "); // note println

String outputFileName = console.nextLine(); // allows spaces

try

{

FileReader reader = new FileReader(inputFileName);

Scanner in = new Scanner(reader);

PrintWriter out = new PrintWriter(outputFileName);

int lineNumber = 1;

while (in.hasNextLine())

{

String line = in.nextLine();

out.println("/* " + lineNumber + " */ " + line);

lineNumber++;

}

out.close();

}

catch (IOException exception)

{

System.out.println("Error processing file: " + exception);

}

// Now print the modified file or examine with Notepad

try

{

FileReader reader = new FileReader(outputFileName);

Scanner in = new Scanner(reader);

while (in.hasNextLine())

{

String line = in.nextLine();

System.out.println(line);

}

}

catch (IOException exception)

{

System.out.println("Error processing file: " + exception);

}

}

}

Input file:

C:\Documents and Settings\Curt\My Documents\School\2006-2007 courses\Java\code\out.txt

Output file:

C:\Documents and Settings\Curt\My Documents\School\2006-2007 courses\Java\code\out2.txt

/* 1 */ There was a young lady named Bright,

/* 2 */ Who could travel much faster than light.

/* 3 */ She set out one day in a relative way,

/* 4 */ And returned on the previous night.

Let's look at more programs that write and read sequential access text files.

We will record files of bank accounts, each account being one record in the file (corresponds to item or row of database). The AccountRecord class below models a bank account, storing an account number, first name, last name, and balance for each account. These fields are the fields or column analogs in a database.

// Deitel: AccountRecord.java

// A class that represents one record of information.

package TextFiles;

public class AccountRecord

{

private int account;

private String firstName;

private String lastName;

private double balance;

// no-argument constructor calls other constructor with default values

public AccountRecord()

{

this( 0, "", "", 0.0 ); // call four-argument constructor

} // end no-argument AccountRecord constructor

// initialize a record

public AccountRecord( int acct, String first, String last, double bal )

{

setAccount( acct );

setFirstName( first );

setLastName( last );

setBalance( bal );

} // end four-argument AccountRecord constructor

// set account number

public void setAccount( int acct )

{

account = acct;

} // end method setAccount

// get account number

public int getAccount()

{

return account;

} // end method getAccount

// set first name

public void setFirstName( String first )

{

firstName = first;

} // end method setFirstName

// get first name

public String getFirstName()

{

return firstName;

} // end method getFirstName

// set last name

public void setLastName( String last )

{

lastName = last;

} // end method setLastName

// get last name

public String getLastName()

{

return lastName;

} // end method getLastName

// set balance

public void setBalance( double bal )

{

balance = bal;

} // end method setBalance

// get balance

public double getBalance()

{

return balance;

} // end method getBalance

// display record

public String toString( )

{

String out = this.getAccount( ) + "\n" + this.getFirstName( ) + "\n" +

this.getLastName( ) + "\n" + this.getBalance( );

return out;

}

} // end class AccountRecord

Below are the files to write and read files.

// AccountWriter.java

package TextFiles;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Scanner;

public class AccountWriter

{

public void put( )

{

Scanner console = new Scanner(System.in);

System.out.println("Output file: "); // note println

String outputFileName = console.nextLine(); // allows for spaces

try

{

PrintWriter out = new PrintWriter(outputFileName);

boolean done = false;

while (!done)

{

System.out.println("Enter account or -1 to quit");

int accountNumber = console.nextInt( );

System.out.println("Enter first name");

String firstName = console.next( );

System.out.println("Enter last name");

String lastName = console.next( );

System.out.println("Enter balance");

double balance = console.nextDouble( );

if(accountNumber == -1)

done = true;

else

{

out.println(accountNumber);

out.println(firstName);

out.println(lastName);

out.println(balance);

}

}

out.close();

}

catch (IOException ioe)

{

System.out.println("Error processing file: " + ioe);

}

}

}

// AccountReader.java

package TextFiles;

import java.io.FileReader;

import java.io.IOException;

import java.util.Scanner;

public class AccountReader

{

public AccountRecord[ ] get( )

{

AccountRecord[ ] myAccounts = new AccountRecord[100];

int index = 0;

Scanner console = new Scanner(System.in);

System.out.println("Input file: "); // note println

String inputFileName = console.nextLine(); // allows for spaces

try

{

FileReader reader = new FileReader(inputFileName);

Scanner in = new Scanner(reader);

while (in.hasNextLine())

{

AccountRecord ar = new AccountRecord( );

ar.setAccount(Integer.parseInt(in.nextLine( )));

ar.setFirstName(in.nextLine( ));

ar.setLastName(in.nextLine( ));

ar.setBalance(Double.parseDouble(in.nextLine( )));

myAccounts[index] = ar;

index++;

}

}

catch (IOException exception)

{

System.out.println("Error processing file: " + exception);

}

AccountRecord[ ] returnAccounts = new AccountRecord[index];

for(int i = 0; i < returnAccounts.length; i++)

{

returnAccounts[i] = myAccounts[i];

}

return returnAccounts;

}

}

// AccountTester.java

package TextFiles;

import java.util.ArrayList;

public class AccountTester

{

public static void main(String[] args)

{

AccountRecord[ ] myAccounts;

AccountWriter aw = new AccountWriter( );

aw.put( );

AccountReader ar = new AccountReader( );

myAccounts = ar.get( );

for(AccountRecord r : myAccounts)

System.out.println(r);

}

}

What if one wants a GUI as opposed to a console program? Use JFileChooser to open and save files as below.

Whatever is entered in the JTextArea is saved to a file when the Save button is clicked.

If one opens a file with the Open button, the text is displayed in the JTextArea.

The Clear button clears all text in the JTextArea.

Below we see the File Dialog box and the code for this program.

/*

* ChoosyFiler.java

*

* Created on November 12, 2005, 2:07 PM

*/

package ChoosyTextSample;

import java.io.*;

import java.util.*;

import javax.swing.*;

import java.awt.*;

/**

*

* @author Curtis Watson

*/

public class ChoosyFiler extends javax.swing.JFrame {

/** Creates new form ChoosyFiler */

public ChoosyFiler() {

initComponents();

setLocationRelativeTo(null);

}

private void jClearButtonActionPerformed(java.awt.event.ActionEvent evt) {

// TODO add your handling code here:

jTextArea.setText("");

}

private void jOpenButtonActionPerformed(java.awt.event.ActionEvent evt) {

// TODO add your handling code here:

JFileChooser fileChooser = new JFileChooser( );

int result = fileChooser.showOpenDialog( this );

if( result == JFileChooser.CANCEL_OPTION)

return;

File fileName = fileChooser.getSelectedFile( );

String line;

String output = "";

Scanner input;

try

{

input = new Scanner(new File( fileName.getCanonicalPath( ) ));

do

{

line = input.nextLine( );

output += line + "\n";

} while ( input.hasNext( ) );

jTextArea.setText(output);

input.close();

}

catch ( IOException iox )

{

System.out.println("Problem reading " + fileName );

}

}

private void jSaveButtonActionPerformed(java.awt.event.ActionEvent evt) {

// TODO add your handling code here:

String input = jTextArea.getText( );

JFileChooser fileChooser = new JFileChooser( );

int result = fileChooser.showSaveDialog( this );

if( result == JFileChooser.CANCEL_OPTION)

return;

File fileName = fileChooser.getSelectedFile( );

PrintWriter outFile;

try

{

outFile = new PrintWriter(new FileWriter(fileName));

}

catch (IOException e)

{

return;

}

outFile.print(input);

outFile.close( );

}

/**

* @param args the command line arguments

*/

public static void main(String args[]) {

java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {

new ChoosyFiler().setVisible(true);

}

});

}

// Variables declaration - do not modify

private javax.swing.JButton jClearButton;

private javax.swing.JButton jOpenButton;

private javax.swing.JPanel jPanel1;

private javax.swing.JButton jSaveButton;

private javax.swing.JTextArea jTextArea;

// End of variables declaration

}

Chapter 15 and 16 Assignments

1. Modify the Fraction class (separate handout) to catch divide by zero exceptions.

Have methods to add, subtract, multiply, and divide fractions. Test the class!

2. Ask a user for employee name, hours worked, and rate of pay. Write to disk.

Read the data from disk, and print paychecks. GUI!

2