Exceptions

The Exceptions Application

The examples in this document all part of the Java Application Exceptions. Download the source archive
Exceptions.zip
Install it as a Java Application with Existing Sources. See the Using NetBeans document for details.

Like others, the Exceptions project has multiple Main Classes intended to illustrate various independent features. The simplest way to run the various classes is to right-click the file and select Run File.

Description

An Exception is an object belonging to a class hierarchy with base class Exception. The very top of this hierarchy is the Throwable class. The idea is that an Exception is "thrown" in the sense that the program control escapes from its progress in the current block and transfers to another appropriate block in which it can continue execution. If none is found, control escapes entirely, often (but not always) terminating the application. It is the job of the programmer to manage these thrown Exceptions, typically through try/catch blocks.

Exceptions are not always beyond the programmer's control. In many cases it is useful to generate exceptions explicitly using the throw statement. Doing so can simplify the program control by avoiding subsequent code steps, obviating the necessity of introducing if/else control structures.

NumsIntoArray

This section explores the example class:
exceptions/NumsIntoArray.java
Consider this Java program:

exceptions.NumsIntoArray
package exceptions;
 
import java.util.Arrays;
import java.util.Scanner;
 
public class NumsIntoArray {
 
  public static void main(String[] args) {
    final int MAX = 3;
    final int SENTINEL = 0;
 
    int nums[] = new int[MAX];
    Scanner keyboard = new Scanner(System.in);
 
    int how_many = 0;
    while (true) {
      System.out.format("enter integer (%s to stop): ", SENTINEL);
      int val = keyboard.nextInt();
 
      if (val == SENTINEL) {
        break;
      }
 
      // store number into array, update position
      nums[how_many++] = val;
    }
 
    System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 0, how_many)));
  }
}
Run this program in 3 ways. Look for Exception information in the Output window:
First, correct
input:
3
4
0
then, error
entries:
3
xx
and
too
many
3
4
5
6
The exceptions from the last two are very different from each other:
  1. The non-integer string "xx" is entered. The exception type is:
    java.util.InputMismatchException
    
    We will call this an expected error, since we cannot count on the user to always type an integer.
  2. More than MAX integers are entered. The exception type is:
    java.lang.ArrayIndexOutOfBoundsException
    
    This is a programming error which should be fixed by inserting the following code within the while loop at an appropriate place:
      if (how_many == MAX) {
        System.out.println("Enough already!");
        break;
      }
    We'll look at the fix in an upcoming section.

File Access Examples

This section explores the example classes:
exceptions/
  ReadFile1.java
  ReadFile2.java
  WriteFile.java
At the top level (seen from the Files window), there is an initial existing file:
sample.txt
We will discuss the File I/O issues later, but we can use the basic read/write access features now.

exceptions.ReadFile1
package exceptions;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
 
public class ReadFile1 {
  public static void main(String[] args) throws IOException {
    File file = new File("nonExistent.txt");
    Path path = file.toPath();
    String content = new String(Files.readAllBytes(path));
    System.out.println(content);
  }
}
Running this yields:
Exception in thread "main" java.nio.file.NoSuchFileException: ...
The exception is along the lines of a program error, i.e., you gave it the wrong file name, or the file does not exist. Simply change it:
File file = new File("sample.txt");

exceptions.ReadFile2
package exceptions;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Scanner;
 
public class ReadFile2 {
  public static void main(String[] args) throws IOException {
    Scanner keyboard = new Scanner(System.in);
 
    System.out.print("Enter file to read: ");
    String filename = keyboard.nextLine().trim();
 
    File file = new File(filename);
    Path path = file.toPath();
    String content = new String(Files.readAllBytes(path));
 
    System.out.println("");
    System.out.println(content);
  }
}
If we give it "sample.txt" at the prompt, it is fine. If not, we get the same exception; however we call this an expected error because the user may simply have typed the file name incorrectly.

exceptions.WriteFile
package exceptions;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Scanner;
 
public class WriteFile {
 
  public static void main(String[] args) throws IOException {
    Scanner keyboard = new Scanner(System.in);
    String content = "Something to write\ninto a file";
 
    System.out.print("Enter file to write to: ");
    String filename = keyboard.nextLine();
 
    File file = new File(filename);
 
    if (file.exists()) {
      System.out.println("overwriting an existing file");
    }
    else {
      System.out.println("creating a new file");
    }
 
    Path path = file.toPath();    
    Files.write(path, content.getBytes());
  }
 
}
Run twice giving the same output file name, something like:
output.txt
This seems to always work. If the file does not exist, it is created, if it does exist it is overwritten. It is actually a bit subtle to make it fail. We will explore that point later.

Text file I/O summary

So you see that text file I/O boils down to just a few steps. It could be written in other ways, but this way suits our needs best. The Java Files class provides We also made use of the boolean function:
file.exists()

The throws clause in a function

The main function in both files requires the additional throws clause:
public static void main(String[] args) throws IOException {
This is necessary because of the usage of the Files functions for reading and writing. If you try removing it, the Files statements will be flagged with a the syntax error message:
unreported exception; must be caught or declared to be thrown

Comparison to NumsIntoArray

If you look back at the NumsIntoArray example, you'll notice that the main function, even though it can throw two exception types, it does not need to declare them as being thrown. This is an odd Java quirk in that certain types of exception, called the RuntimeExceptions do not need to be declared. This class includes the ones seen plus others, which include:
java.util.InputMismatchException
java.util.ArrayIndexOutOfBoundsException
java.lang.NumberFormatException          (numeric parse functions)
java.util.regex.PatternSyntaxException   (bad regex pattern)

Try/catch block

Dealing with exceptions means that you want to "catch" them before the control leaves the section where they are generated. All expected exception should be identified and dealt with in this way.

The key ingredient it the Java try/catch block:
try {
  // exception-generating code
} 
catch(SomeExceptionType ex) {
  // do something with ex
}
Minimally, only exception-generating statements need to be placed into the try block, but it is often convenient to place larger sections of code into the try block. If an exception is generated, control immediately leaves the try block and attempts to enter the catch block by "matching" the type of the generated exception to the SomeExceptionType in the catch block. If it cannot match the type, it goes on past the try-catch block.

If the generated exception type does match SomeExceptionType, then control enters the catch block; if not, control skips over the catch block. Likewise, if no exceptions are thrown in the try block, control skips over the catch block.

The "do something with ex" suggested in the outline can represent a variety of possibilities like: The most general exception handling try-catch block uses Exception in the catch block:
try {
  // exception-generating code
} 
catch(Exception ex) {
  // do something with ex
}
Every exception type matches Exception. This notion of an exception type "matching" another will be clarified later.

NetBeans Formatting

By default NetBeans prefers to start "chained" blocks on the same line with the end brace of the previous block, like this:
try {
  // ...    
} catch (Exception ex) {
  // ...
}
or
if (...) {
  // ...    
} else {
  // ...
}
I tend to prefer a more spacious-looking layout, especially for try/catch blocks:
try {
  // ...    
} 
catch (Exception ex) {
  // ...
}
To change the default NetBeans behavior,
  1. Select Tools ⇒ Options, or on the MAC: NetBeans ⇒ Preferences.
  2. Choose Editor and then the Formatting tab.
  3. Within this window, choose:
    Language:
    Formatting:
    In the New Lines section, check these checkboxes:
    "catch"
    "finally"
    "else" (optional)
  4. Click OK to leave.

NetBeans Shortcut

It is very helpful to use the following NetBeans shortcut:
trycatch[TAB]
which generates this code:
try {
 
} 
catch (Exception e) {
}

ReadFile programs with Exception Handling

Both modifications are also in the corrected package.

ReadFile1 ⇾ ReadFile1Handled


corrected.ReadFile1Handled
package corrected;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
 
public class ReadFile1Handled {
  public static void main(String[] args) {
    File file = new File("nonExistent.txt");
    Path path = file.toPath();
    String content = null;
    try {
      content = new String(Files.readAllBytes(path));    
    }
    catch (IOException ex) {
      //System.err.println(ex.getMessage());
      ex.printStackTrace(System.err);
      System.exit(1);
    }
    System.out.println(content);
  }
}
The first thing to observe is that the main function now longer declares
throws IOException
because our code has dealt with the exception in the try/catch block. The effect is the same as if previous version.

This coding style represents a minimal usage of try/catch; only the one exception-generating statement is in the try block. The idea being:
Get the exceptions out of the way and then go on to the main program
Unfortunately, doing so makes the code a bit convoluted. Netbeans complains about the declaration of content no matter what you do. With the way it is written as
String content = null;
Netbeans flags the line as a warning saying that the assigned value (null) is never used. But if you try to omit the assignment as:
String content;
then NetBeans flags the final println line as an error, saying that content might not have been initialized!

In some sense, when using try/catch, it is better to simply move the entire program inside the try block:
  public static void main(String[] args) {
    try {
      File file = new File("nonExistent.txt");
      Path path = file.toPath();
      String content = new String(Files.readAllBytes(path));
      System.out.println(content);
    }
    catch (IOException ex) {
      //System.err.println(ex.getMessage());
      ex.printStackTrace(System.err);
      System.exit(1);
    }
  }



ReadFile2 ⇾ ReadFile2Handled

In this second version we want to deal with the expected error by allowing the user to correct a typing mistake for the desired file. We introduce a loop to permit a correction with a way out if the user wants to give up.

corrected.ReadFile2Handled
package corrected;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Scanner;
 
public class ReadFile2Handled {
 
  public static void main(String[] args) throws IOException {
    Scanner keyboard = new Scanner(System.in);
 
    while (true) {
      try {
        System.out.print("Enter file to read (empty to skip): ");
        String filename = keyboard.nextLine();
        if (filename.isEmpty()) {
          // key in an empty line
          return;
        }
 
        File file = new File(filename);
        Path path = file.toPath();
        String content = new String(Files.readAllBytes(path));
 
        // success, print it and get out
        System.out.println("");
        System.out.println(content);
        return;
      }
      catch (Exception ex) {
        System.out.println("file does not exist, try again.");
      }
    }
  }
}
As mentioned earlier, there is one valid file available:
sample.txt
This is written with the try/catch block inside the loop. If you stay in the loop, one way or another you will terminate the program: Instead of return, we could just as well use:
break;
The way to stay in the loop is to throw an Exception from a file read mistake, landing in the catch block. If you feel uncomfortable about transferring control out of a loop, you can do this:
    boolean done = false;
    while (!done) {
      try {
        System.out.print("Enter file to read (empty to skip): ");
        String filename = keyboard.nextLine();
        if (!filename.isEmpty()) {
          File file = new File(filename);
          Path path = file.toPath();
          String content = new String(Files.readAllBytes(path));
 
          System.out.println("");
          System.out.println(content);
        }
        done = true;
      }
      catch (Exception ex) {
        System.out.println("file does not exist, try again.");
      }
    }

Exceptions in Event Handlers

Exceptions in event handlers of GUI programs must be identified, caught and dealt with by try/catch blocks. If they are uncaught, the behavior is unpredictable; the program will print error messages in a console window, but if the GUI is being run outside of an IDE, the console may not bee "seen." Most likely the program will just continue on, but with the wrong behavior.

If you have:
frame.getSomeButton().addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent ae) {
    /* exception generating statements */
  }
});
There is no mechanism to throw exceptions them "up the chain," so to speak, say, like this:
  public void actionPerformed(ActionEvent ae) throws Exception {
    /* exception generating statements */
  }
You are obligated to write a try-catch block:
  public void actionPerformed(ActionEvent ae) {
    try {
      /* exception generating statements */
    catch (...) { 
      ... 
    }    
  }

RegexMatcher

We have incorporated the code of the RegexMatcher into Exceptions in its unfixed form as:
exceptions.RegexMatcher
views.RegexMatcherFrame
Run RegexMatcher, enter this incomplete regular expression into the regex field:
[a
Then type something into the sample string field. Look for the exception in the output window:
Exception ... java.util.regex.PatternSyntaxException: ...
The PatternSyntaxException is a RuntimeException which we talked about previously. It is generated by the matches function, but the Java compiler gives no indication that this can be thrown.

As you see, the program continues on, but we want to tell the user that there is an error in the regular expression. The code indicates what the try-catch block which should be put into effect:

exceptions.RegexMatcher (except)
      @Override
      public void keyReleased(KeyEvent ke) {
//        try {
          String regex = frame.getRegexField().getText();
          String test_str = frame.getSampleStringField().getText();
          String report;
          if (test_str.matches(regex)) {
            report = "yes";
          }
          else {
            report = "no";
          }
          frame.getReportField().setText(report);
//        }
//        catch (PatternSyntaxException ex) {
//          JOptionPane.showMessageDialog(frame, 
//                  "Regex error: " + ex.getMessage());
//        }
      }
    });
As we indicated above, we could just as well write the catch section as:
catch (Exception ex) { ... }

Accumulator

Here is another GUI example which deals with invalid integer entries in a textfield.
exceptions.Accumulator     (controller class)
views.AccumulatorFrame     (GUI Frame form class)
The frame looks like this:
Named Components
⇐  value
⇐  accum
⇐  accumValue, clear
These are the Frame's interface access methods:

views.AccumulatorFrame
...
public class AccumulatorFrame extends javax.swing.JFrame {
 
  public JButton getAccumButton() {
    return accum;
  }
 
  public JButton getClearButton() {
    return clear;
  }
 
  public JTextField getValueTextField() {
    return value;
  }
 
  public JTextField getAccumValueTextField() {
    return accumValue;
  }
 
  ...
}
The driver program, with exception handling commented out, is this:

exceptions.Accumulator
package exceptions;
 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import views.AccumulatorFrame;
 
public class Accumulator {
 
  private final AccumulatorFrame frame = new AccumulatorFrame();
 
  public Accumulator() {
    frame.setTitle(getClass().getSimpleName());
 
    frame.getAccumValueTextField().setText("0");
 
    frame.getAccumButton().addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent ae) {
//        try {
          String valueText = frame.getValueTextField().getText().trim();
          System.out.println(valueText);
          String accumValueText = frame.getAccumValueTextField().getText();
          int value = Integer.parseInt(valueText);
          int accumValue = Integer.parseInt(accumValueText);
          accumValue += value;
          frame.getAccumValueTextField().setText(String.valueOf(accumValue));
//        } catch (NumberFormatException ex) {
//          String message = "Invalid New Value input";
//          JOptionPane.showMessageDialog(frame, message);
//        }
      }
    });
 
    frame.getClearButton().addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent ae) {
        frame.getValueTextField().setText("");
        frame.getAccumValueTextField().setText(String.valueOf(0));
      }
    });
  }
 
  public static void main(String[] args) {
    Accumulator app = new Accumulator();
    app.frame.setVisible(true);
  }
}
Try running as is. The empty field for "New Value" will generate an exception. You'll see report of exception, but the application does not terminate. Keep going, entering integer values in the "New Value" field and observe that it is still working.

Next, uncomment the 5 lines which make up the try/catch block and re-run. This time an error message is given whenever the "New Value" field is not an integer.

NumsIntoArray with Exception Handling

Let's consider some fixes to the first program. You'll find these in the corrected package.

First fix: NumsIntoArrayHandled1

Here is our first approach, along the lines of the minimalistic style of putting only the exception-causing statement in a try/catch block:

corrected.NumsIntoArrayHandled1
package corrected;
 
import java.util.Arrays;
import java.util.Scanner;
import java.util.InputMismatchException;
 
public class NumsIntoArrayHandled1 {
 
  public static void main(String[] args) {
    final int MAX = 3;
    final int SENTINEL = 0;
 
    int nums[] = new int[MAX];
    Scanner keyboard = new Scanner(System.in);
 
    int how_many = 0;
    while (true) {
      System.out.format("enter integer (%s to stop): ", SENTINEL);
      int val;
 
      try {
        val = keyboard.nextInt();
      }
      catch (InputMismatchException ex) {
        System.err.println("-- integer not entered");
        keyboard.nextLine();     // skip the line
        //keyboard.skip(".*");   // regex alternative
        continue;
      }
 
      if (val == SENTINEL) {
        break;
      }
 
      nums[how_many++] = val;
 
      if (how_many == MAX) {
        System.out.println("Enough already!");
        break;
      }
    }
 
    System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 0, how_many)));
  }
}
This approach encloses the one exception-generating statement:
int val = keyboard.nextInt();
into a try-catch block:

corrected.NumsIntoArrayHandled1
    while (true) {
      System.out.format("enter integer (%s to stop): ", SENTINEL);
      int val;
      try {
        val = keyboard.nextInt();
      } 
      catch (InputMismatchException ex) {
        System.err.println("-- integer not entered");
        keyboard.nextLine();     // skip the line
        //keyboard.skip(".*");   // regex alternative
        continue;
      }
      // use val here
      ...
Note that the declaration
int val;
must be separated from the statement
val = keyboard.nextInt();
because we need to use it after the try/catch block has completed.

Suppose, at the prompt you type the invalid input:
xx 55
What we want to do is recognize the mistake and skip over this input line. The key feature is the function:
keyboard.nextLine()
It is used without need of capturing the content, just move past the line. A suggested alternative is
keyboard.skip(regex)
where the regex we want use is ".*" which matches anything on one line. The suggested usage:
keyboard.skip(".*")
skips every character up to, but not including, the subsequent newline, and so the behavior is not exactly the same as:
keyboard.nextLine()
These events will happen for the invalid input:
  1. Then keyboard.nextInt() call sees the "xx", leaving the scanner just before the "xx", throwing an exception.,
  2. Upon entering the catch block, the keyboard.nextLine() operation makes the scanner "skip" the entire line.
A key point is that the scanner does not go past the invalid input, "xx" and so if you do not skip the line, you'll be in an infinite loop.

Rewrite: NumsIntoArrayFix1A

The usage of break in a loop is an "issue", but this first version also has a continue. We can, however, avoid the continue with the approach of putting all the loop code within the try/catch block and conforming to this general style:
while(...) {
  try {
    // loop code which generates exceptions
  } 
  catch(...) {
  }	
}
A break or return will leave the loop, an exception will jump to the catch block, handle it and go back and try again. Here is the rewritten version:

corrected.NumsIntoArrayHandled1A
package corrected;
 
import java.util.Arrays;
import java.util.Scanner;
import java.util.InputMismatchException;
 
public class NumsIntoArrayHandled1A {
 
  public static void main(String[] args) {
    final int MAX = 3;
    final int SENTINEL = 0;
 
    int nums[] = new int[MAX];
    Scanner keyboard = new Scanner(System.in);
 
    int how_many = 0;
    while (true) {
      try {
        System.out.format("enter integer (%s to stop): ", SENTINEL);
        int val = keyboard.nextInt();
 
        if (val == SENTINEL) {
          break;
        }
 
        nums[how_many++] = val;
 
        if (how_many == MAX) {
          System.out.println("Enough already!");
          break;
        }
      }
      catch (InputMismatchException ex) {
        System.err.println("-- integer not entered");
        //keyboard.skip(".*");   // regex alternative
        keyboard.nextLine();
      }
    }
 
    System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 0, how_many)));
  }
}

Another issue

Consider either of the above two "solutions" we have so far and run the following tests, entering this content at two prompts. First,
55 66
0
then,
55 xx
0
For both, you will see an odd response from NetBeans. What is happening is that If you change
System.err.println
to
System.out.println
, you will see the more expected ordering of messages. Nevertheless, it is confusing regardless of the output order.

Second fix: NumsIntoArrayFix2

The approach deals with the problem detailed in the last sub-section. The idea is to read the entire line first with:
String line = keyboard.nextLine()
instead of asking for an int. Then "parse" the line with the idea that it should contain a single integer. Here is the program:

corrected.NumsIntoArrayFix2
package corrected;
 
import java.util.Arrays;
import java.util.Scanner;
 
public class NumsIntoArrayHandled2 {
 
  public static void main(String[] args) {
    final int MAX = 3;
    final int SENTINEL = 0;
 
    int nums[] = new int[MAX];
    Scanner keyboard = new Scanner(System.in);
 
    int how_many = 0;
    while (true) {
      try {
        System.out.format("enter integer (%s to stop): ", SENTINEL);
        int val;
        String line = keyboard.nextLine().trim();
        val = Integer.parseInt(line);
 
        if (val == SENTINEL) {
          break;
        }
 
        nums[how_many++] = val;
 
        if (how_many == MAX) {
          System.out.println("Enough already!");
          break;
        }
      }
      catch (NumberFormatException ex) {
        System.err.println("-- integer not entered");
      }
    }
 
    System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 0, how_many)));
  }
}
Try running it with the input:
55 xx
You will see that the entire line is rejected. This version employs the very useful Integer.parseInt function which convert a String into an int. If the line entered is not an integer, it throws an exception of this type:
java.lang.NumberFormatException

Multiple Catch Blocks

A try-catch statement can have multiple catch blocks reflecting the different types of Exceptions generated by the code within the try block:
try {
  // exception-generating code
} 
catch(ExceptionType1 ex) {
  // ...
} 
catch(ExceptionType2 ex) {
  // ...
}
...
When an exception is generated within the try block, the exception class is "matched" against the list of exception classes from the catch blocks in sequence. The sense of "matching" is will be discussed later in the course.

All exception classes "match" the Exception class and so a general approach to exception handling is to use the following code to ensure that all exceptions will be caught:
try {
  // exception-generating code
} 
catch(ExceptionType1 ex) {
  // ...
} 
catch(ExceptionType2 ex) {
  // ...
} 
...
catch(Exception ex) {
  // this block will catch any uncaught exception
}
You should, however, try to identify precisely the expected exception types which could be generated and use only those types. The final catch(Exception ex) block can be used for catching runtime errors which you have overlooked, or, as we see later, for catching user-generated exceptions.

Order of catch blocks

The catch(Exception ex), if used, must be the last catch block; NetBeans will readily mark the compiler error if you try to add another catch block after it. In fact the ordering if exception types is important in other circumstances as well. We will need to know about inheritance to have a full understanding.

Throwing an Exception

You can programmatically throw an exception using the statement:
throw new ExceptionType("my message");
Any exception type can be used, but the various types have intended usages. If you manage exception handling closely by the types, then the top-level Exception class can be used for user-generated exceptions created by explicit throw statements; i.e., to throw an exception, use
throw new Exception("my message");

Example

Here is an example of a user-generated exception. Suppose we want to enter non-negative integers, one-per-line, and sum them with sentinel 0. We'll employ the structure from the NumsIntoArrayFix2 application.

exceptions.SumInts
package exceptions;
 
import java.util.Scanner;
 
public class SumInts {
 
  public static void main(String[] args) {
    final int SENTINEL = 0;
 
    Scanner keyboard = new Scanner(System.in);
 
    int sum = 0;
    while (true) {
      try {
        System.out.format("enter integer (%s to stop): ", SENTINEL);
        String line = keyboard.nextLine().trim();
 
        int val = Integer.parseInt(line);
        if (val < 0) {
          throw new Exception("-- cannot enter a negative number");
        }
 
        if (val == SENTINEL) {
          break;
        }
        sum += val;
      }
      catch (NumberFormatException ex) {
        System.err.println("-- input line is not an integer");
      }
      catch (Exception ex) {
        System.err.println(ex.getMessage());
      }
    }
    System.out.println("sum = " + sum);
  }
}
One reason that it is useful to separate the two exception types is that the exception message generated by parseInt is not very informative.

Alternative using regular expression matching

Since we know about regular expressions, we can use that information to see if the line entered is an integer prior to calling Integer.parseInt, thereby ensuring that this function will not throw an exception. The regular expression we're looking for is:
[+-]?\d+
The "[+-]" means either "+" or "-" and by appending the quantifier ?, the meaning is:
an optional "+" or "-" followed by a digit sequence
Our program employs only user-generated exceptions. The alternative version replaces the top part of the while loop in the previous version by this:

exceptions.SumIntsRegex
package exceptions;
 
import java.util.Scanner;
 
public class SumIntsRegex {
 
  public static void main(String[] args) {
    final int SENTINEL = 0;
 
    Scanner keyboard = new Scanner(System.in);
 
    int sum = 0;
    while (true) {
      try {
        System.out.format("enter integer (%s to stop): ", SENTINEL);
        String line = keyboard.nextLine().trim();
 
        if (!line.matches("[+-]?\\d+")) {
          throw new Exception("-- input line is not an integer");
        }
        int val = Integer.parseInt(line);
        if (val < 0) {
          throw new Exception("-- cannot enter an neg. number");
        }
 
        if (val == SENTINEL) {
          break;
        }
        sum += val;
      }
      catch (Exception ex) {
        System.err.println(ex.getMessage());
      }
    }
    System.out.println("sum = " + sum);
  }
}

The try/catch/finally structure

To complete the try/catch structure, a finally block can be added at the end:
try {
  // exception-generating code
} 
catch(ExceptionType1 ex) {
  // do something with ex
} 
catch(ExceptionType2 ex) {
  // do something with ex
}
...
finally {
  // actions which ALWAYS occur unless program exits
}
The purpose of the finally block is to provide a mechanism by which certain statements can always be executed regardless of whether an exception occurs or not and regardless of whether the code transfers control away or not (like when return is used).

Here is a demo program which illustrates most of the control possibilities:

exceptions.TestFinally
package exceptions;
 
import java.util.NoSuchElementException;
import java.util.Scanner;
 
public class TestFinally {
 
  public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);
 
    int testVal = 0;
    System.out.format("Enter integer test value 1-5: ");
    try {
      String line = keyboard.nextLine().trim();
      testVal = Integer.parseInt(line);
      if (testVal < 1 || testVal > 5) {
        System.err.println("-- Wrong value.");
        System.exit(1);
      }
    }
    catch (NumberFormatException ex) {
      System.err.println("-- Input ine is not an integer, exiting.");
      System.exit(1);
    }
 
    try {
      System.out.println("\nEnter try block.\n");
      if (testVal == 1) {
        System.out.println("No exception thrown. Fall through try block.\n");
      }
      else if (testVal == 2) {
        System.out.println("No exception thrown. Call return.\n");
        return;
      }
      else if (testVal == 3) {
        System.out.println("No exception thrown. Call exit.\n");
        System.exit(0);
      }
      else if (testVal == 4) {
        System.out.println("Throw a NoSuchElementException.\n");
        throw new NoSuchElementException("thrown");
      }
      else if (testVal == 5) {
        System.out.println("Throw an Exception.\n");
        throw new Exception("thrown");
      }
    }
    catch (NoSuchElementException ex) {
      System.out.println("In NoSuchElementException block. Fall through.\n");
    }
    catch (Exception ex) {
      System.out.println("In Exception block. Call return.\n");
      return;
    }
    finally {
      System.out.println("In finally block.\n");
    }
    System.out.println("After try catch block.\n");
  }
}
Here are the (condensed and highlighted) outputs you get from runs with legitimate test value inputs:
Enter integer test value 1-5: 1
Enter try block.
No exception thrown. Fall through try block.
In finally block.
After try catch block.

Enter integer test value 1-5: 2 Enter try block. No exception thrown. Call return. In finally block.
Enter integer test value 1-5: 3 Enter try block. No exception thrown. Call exit.
Enter integer test value 1-5: 4 Enter try block. Throw a NoSuchElementException. In NoSuchElementException block. Fall through. In finally block. After try catch block.
Enter integer test value 1-5: 5 Enter try block. Throw an Exception. In Exception block. Call return. In finally block.
The conclusion from this experiment is that the finally block is always called unless the code exits the program. In contrast the presence of return or other control statements means that code after the try/catch/finally block may not be executed.

Here is a second program which illustrates the finally clause being called in the presence of break and continue within a loop. There are 3 different behaviors based on:

exceptions.TestFinally2
package exceptions;
 
import java.util.Scanner;
 
public class TestFinally2 {
 
  public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);
 
    while(true) {
      try {
        System.out.print("==> ");
        String line = keyboard.nextLine().trim();
        if (line.isEmpty()) {
          System.out.println("in try block: break");
          break;
        }
 
        Integer.parseInt(line);
 
        throw new Exception();
      }
 
      catch (NumberFormatException ex) {
        System.out.println("parseInt exception: break");
        break;
      }
      catch (Exception ex) {
        System.out.println("regular exception: continue");
        continue;
      }
      finally {
        System.out.println("in finally");
      }
    }
  }
}

Practice Problems

AddIntsFromLines

Write a program, samples.AddIntsFromLines, which reads multiple lines from the keyboard. Each line can consist of multiple integers, but can also have strings which are not invalid integers. The goal is to compute the sum of all the valid integers up to the first 0 (sentinel), and then report the sum and the number of invalid strings seen. Use the Scanner member function:
skip(regex)
to move past the invalid strings. Here is a sample run:
Enter integers to be summed:
2 4 xx 5 x6 
yy 8 7a
-3 0 3333
-------------
sum = 16
invalid entries: 4
The starting point is the program which works if there are no invalid strings:

samples.AddIntsFromLines (starter)
package samples;
 
import java.util.Scanner;
 
public class AddIntsFromLines {
 
  public static void main(String[] args) {
    final int SENTINEL = 0;
 
    Scanner keyboard = new Scanner(System.in);
 
    int sum = 0;
    int invalid_count = 0;
    System.out.println("Enter integers to be summed:");
 
    while (true) {
      int val = keyboard.nextInt();
 
      if (val == SENTINEL) {
        break;
      }
      sum += val;
    }
 
    System.out.println("-------------");
    System.out.println("invalid entries: " + invalid_count);
    System.out.println("sum = " + sum);
  }
}
select


© Robert M. Kline