第十四章

例外處理

14.1 丟出例外

錯誤碼

例外

例外類別階層


Syntax 14.1: Throwing an Exception

  throw exceptionObject;

Example:

 
throw new IllegalArgumentException();

Purpose:

To throw an exception and transfer control to a handler for this exception type

14.2 受檢查的例外情形

受檢查及未受檢查的例外



註明例外

Syntax 14.2: Exception Specification

  accessSpecifier returnType methodName(parameterType parameterName, . . .)
throws ExceptionClass, ExceptionClass . . .

Example:

  public void read(BufferedReader in) throws IOException

Purpose:

To indicate the checked exceptions that a method can throw

14.3 設計自己的例外型式

14.4 接住例外

每一例外都必須處理。 另一種例外處理方式是使用 try/catch 敘述。 把需要例外處理的程式碼放在 try 方塊內, 而把處理例外的程式碼放在 catch 方塊中。
try
{
   BufferedReader in = new BufferedReader(
      new InputStreamReader(System.in));
   System.out.println("How old are you?");
   String inputLine = in.readLine();
   int age = Integer.parseInt(inputLine);
   age++;
   System.out.println("Next year,you'll be " + age);
}
catch (IOException exception)
{
   System.out.println("Input/output error " +exception);
}
catch (NumberFormatException exception)
{
   System.out.println("Input was not a number");
}

Syntax 14.3: General Try Block

 
try 
{
statement
statement

...
}
catch (ExceptionClass exceptionObject)
{
statement
statement
...
}
catch (ExceptionClass exceptionObject)
{
statement
statement
...
}
...

Example:

 
try 
{
System.out.println("What is your name?");
String name = console.readLine();
System.out.println("Hello,"+name +"!");
}
catch (IOException exception)
{
exception.printStackTrace();
System.exit(1);
}

Purpose:

To execute one or more statements that may generate exceptions. If an exception of a particular type occurs, then stop executing those statements and instead go to the matching catch clause. If no exception occurs, then skip the catch clauses.

14.5 finally 子句

Syntax 14.4: finally 子句

  try
{
   statement
   statement

   ...
}
finally
{
   statement
   statement

   ...
}

Example:

 
BufferedReader in = null; 
try
{
in = new BufferedReader(
new FileReader(filename));
purse.read(in);
}
finally
{
if (in !=null) in.close();
}

Purpose:

To execute one or more statements that may generate exceptions, and to execute the statements in the finally clause whether or not an exception occured. 

14.6 完整的例題

The read method of the Coin class

public boolean read(BufferedReader in) throws IOException
{
   String input =in.readLine();
   if (input == null) // normal end of file
      return false;
   value = Double.parseDouble(input);
      // may throw unchecked NumberFormatException 
   name = in.readLine();
   if (name == null) // unexpected end of file 
      throw new EOFException("Coin name expected");
   return true;
}

The read method of the Purse class

public void read(BufferedReader in)
   throws IOException
{
   boolean done = false;
   while (!done)
   {
      Coin c = new Coin();
      if (c.read(in)) add(c);
      else done =true;
   }
}

The readFile method of the Purse class

public void readFile(String filename)
   throws IOException
{
   BufferedReader in = null;
   try
   {
      in = new BufferedReader(
         new FileReader(filename));
      read(in);
   }
   finally
   {
      if (in != null)
      in.close();
   }
}

User interaction in main

boolean done = false;
String filename = JOptionPane.showInputDialog("Enter file name");
while (!done)
{
   try
   {
      Purse myPurse = new Purse();
      myPurse.readFile(filename);
      System.out.println("total=" + myPurse.getTotal());
      done =true;
   }
   catch (IOException exception)
   {
      System.out.println("Input/output error " + exception);
   }
   catch (NumberFormatException exception)
   {
      exception.printStackTrace(); // error in file format
   }
   if (!done)
   {
      filename = JOptionPane.showInputDialog( "Try another file:");
      if (filename == null)
         done =true;
   }
}

Scenario

  1.  PurseTest.main calls Purse.readFile
  2. Purse.readFile calls Purse.read
  3. Purse.read calls Coin.read
  4. Coin.read throws an EOFException
  5. Coin.read has no handler for the exception and terminates immediately. 
  6. Purse.read has no handler for the exception and terminates immediately
  7. Purse.readFile has no handler for the exception and terminates immediately after executing the finally clause and closing the file. 
  8. PurseTest.main has a handler for an IOException , a superclass of EOFException. That handler prints a message to the user. Afterwards, the user is given another chance to enter a file name. Note that the statement printing the purse total has been skipped.

File PurseTest.java


import javax.swing.JOptionPane;
import java.io.IOException;

/**
   This program prompts the user to enter a file name
   with coin values. A purse object is filled with
   the coins specified in the file. In case of an exception,
   the user can choose another file.
*/
public class PurseTest
{
   public static void main(String[] args)
   {
      boolean done = false;
      String filename
         = JOptionPane.showInputDialog("Enter file name");

      while (!done)
      {
         try
         {
            Purse myPurse = new Purse();
            myPurse.readFile(filename);
            System.out.println("total=" + myPurse.getTotal());
            done = true;
         }
         catch (IOException exception)
         {
            System.out.println("Input/output error " + exception);
         }
         catch (NumberFormatException exception)
         {
            exception.printStackTrace();
         }

         if (!done)
         {
            filename = JOptionPane.showInputDialog(
               "Try another file:");
            if (filename == null) done = true;
         }
      }
      System.exit(0);
   }
}


File Purse.java


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

/**
   A purse computes the total of a collection of coins.
*/
public class Purse
{
   /**
      Constructs an empty purse.
   */
   public Purse()
   {
      total = 0;
   }

   /**
      Read a file with coin descriptions and adds the coins
      to the purse.
      @param filename the name of the file
   */
   public void readFile(String filename)
      throws IOException
   {
      BufferedReader in = null;
      try
      {
         in = new BufferedReader(new FileReader(filename));
         read(in);
      }
      finally
      {
         if (in != null) in.close();
      }
   }

   /**
      Read a file with coin descriptions and adds the coins
      to the purse.
      @param in the buffered reader for reading the input
   */
   public void read(BufferedReader in)
      throws IOException
   {
      boolean done = false;
      while (!done)
      {
         Coin c = new Coin();
         if (c.read(in))
            add(c);
         else
            done = true;
      }
   }

   /**
      Add a coin to the purse.
      @param aCoin the coin to add
   */
   public void add(Coin aCoin)
   {
      total = total + aCoin.getValue();
   }

   /**
      Get the total value of the coins in the purse.
      @return the sum of all coin values
   */
   public double getTotal()
   {
      return total;
   }

   private double total;
}



File Coin.java


import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;

/**
   A coin with a monetary value.
*/
public class Coin
{
   /**
      Constructs a default coin.
      Use the read method to fill in the value and name.
   */
   public Coin()
   {
      value = 0;
      name = "";
   }

   /**
      Constructs a coin.
      @param aValue the monetary value of the coin.
      @param aName the name of the coin
   */
   public Coin(double aValue, String aName)
   {
      value = aValue;
      name = aName;
   }

   /**
      Reads a coin value and name.
      @param in the reader
      @return true if the data was read,
      false if the end of the stream was reached
   */
   public boolean read(BufferedReader in)
      throws IOException
   {
      String input = in.readLine();
      if (input == null) return false;
      value = Double.parseDouble(input);
      name = in.readLine();
      if (name == null)
         throw new EOFException("Coin name expected");
      return true;
   }

   /**
      Gets the coin value.
      @return the value
   */
   public double getValue()
   {
      return value;
   }

   /**
      Gets the coin name.
      @return the name
   */
   public String getName()
   {
      return name;
   }

   private double value;
   private String name;
}