Welcome to Lesson 16 - Part 2!
|
Method | Description |
---|---|
getMessage() | Returns the message associated with the exception, if available. |
printStackTrace() | Prints the stack trace to the standard error stream. |
toString() | Returns a string with the name of the exception class along with the message associated with the exception, if available. |
What Exceptions Can Occur?
- The are two usual ways to determine what exceptions can occur in a program
- The first way is to try the code and see what happens
- If we tried to code our TotalCalculator program without a
try-catch
:Scanner input = new Scanner(System.in); double cost = 0, tax = 0; System.out.print("Enter cost: "); cost = input.nextDouble(); System.out.print("Enter tax: "); tax = input.nextDouble(); double total = cost + tax; System.out.println("Total: " + total); System.out.println("Thanks for paying!");
- We found we could get a an exception like:
Enter cost: $100
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:840)
at java.util.Scanner.next(Scanner.java:1461)
at java.util.Scanner.nextDouble(Scanner.java:2387)
at TotalCalculator1.main(TotalCalculator1.java:9)
- This tells you that you need to code a
try-catch
for anInputMismatchException
- Sometimes you might want to know what the possible exceptions are possible in your code
- To find out, you can look up exceptions in the Java API
- For example, you can look up the documentation for the
Scanner
method: nextDouble() - You then examine the list of possible exceptions and determine if and how they might occur in your program
Using the throws
Clause
- Anytime your program uses a method that can cause a checked exception or throws an unchecked exception, your program must do something with it.
- You have two options:
- Handle the exception using a try-catch
- Throw the exception to another method or to the general exception handler
- If you decide the method cannot handle the exception, you use a
throws
clause to send the exception to the caller - The general syntax for throwing an exception:
[accessModifier] returnType methodName(parameterList) throws ExceptionType1, ExceptionType2,... { // statements }
- Where:
- accessModifier: determines which classes can access this method
- returnType: the type of value returned by the method, or
void
for no return value - methodName: the name you make up for the method
- parameterList: the types and names of the parameters
- ExceptionTypeX: the type of exception a method throws
- For example:
public void printArrayFile(File f) throws IOException {
PrintWriter pw = new PrintWriter(f)
for (int i = 0; i < numElements; i++) {
pw.println(array[i]);
} pw.close();
} - Throwing an exception is like passing the buck:
- Requires the calling method to deal with the exception
- The calling method can also throw the exception
- Eventually some method should catch it or the general exception handler is called
How Exceptions are Propagated
- When methods cannot handle an exception, that method should throw the exception
- The user of the method can then decide how to handle the exception
- Methods can call other methods that can throw an exception
- This chain continues usually until one method catches the exception
- If no method catches the exception, then the general exception handler will print an error message at runtime.
Example of Exception Propagation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class ExceptionPropogation {
public static void main(String[] args) {
methodD();
}
public static void methodD() {
try {
methodC();
} catch (Exception e) {
System.out.println("Caught exception in D");
|
Throwing Exceptions
- You may be wondering how the code in
Scanner
and other classes generates an exception - The answer is the Java
throw
statement - Syntax:
throw new ThrowableObject
- Where:
- ThrowableObject: the exception class to throw
- For example:
throw new Exception("Exception message");
- Note that throw is a Java keyword, which should be followed by an Exception object.
- In the above example, throw is followed by a call to the Exception constructor
- Typically, you decide to throw an exception after checking for an error condition:
if (cost < 0) { throw new Exception( "Cost cannot be less than 0"); }
- To demonstrate, let us throw an exception in an example program
Example Program Using throw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import java.util.Scanner;
|
- Note the use the
getMessage()
method to explain the error - There are a few other commonly used exception methods shown in the table below
- Note that the line of code above to clear the buffer is not strictly necessary here as the tax value has already been read into the variable before throwing the exception.
- However, in the prior example, it was required to clear the erroneous input from the buffer, which we were not able to read into the variable:
try {
System.out.print("Enter cost: ");
cost = input.nextDouble(); //a String cannot be read into this variable
System.out.print("Enter tax: ");
tax = input.nextDouble(); //a String cannot be read into this variable
double total = cost + tax;
System.out.println("Total: " + total);
more = false;
} catch(InputMismatchException e) {
System.out.println(
"Error -- enter digits only!");
input.nextLine(); // clear the buffer (required)
}
- When you write a method, you have the option to let this method throw an exception.
- When writing a method that throws an exception, you should add a throws clause to the method signature
- This alternation to the signature will cause an @throws tag to be added to the Javadoc comment
- Then, as part of the method body, you should throw the stated exception:
/**
* Computes the sum of the values at two
* indices of the ArrayList
* @param scores the ArrayList of scores
* @param index1 the first index
* @param index2 the second index
* @return the sum of the values at the two indices
* @throws IndexOutOfBoundsException when
* 0 > index1 || index1 >= size
* 0 > index2 || index2 >= size
*/
public static double getIndexSum
(ArrayList<Double> scores, int index1, int index2) throws IndexOutOfBoundsException{
if (index1 < 0 || index1 >= scores.size()) {
throw new IndexOutOfBoundsException(index1
+ " is outside the bounds of the ArrayList");
} else if (index2 < 0 || index2 >= scores.size()) {
throw new IndexOutOfBoundsException(index2
+ " is outside the bounds of the ArrayList");
} else {
return scores.get(index1) + scores.get(index2);
}
}
* Computes the sum of the values at two
* indices of the ArrayList
* @param scores the ArrayList of scores
* @param index1 the first index
* @param index2 the second index
* @return the sum of the values at the two indices
* @throws IndexOutOfBoundsException when
* 0 > index1 || index1 >= size
* 0 > index2 || index2 >= size
*/
public static double getIndexSum
(ArrayList<Double> scores, int index1, int index2) throws IndexOutOfBoundsException{
if (index1 < 0 || index1 >= scores.size()) {
throw new IndexOutOfBoundsException(index1
+ " is outside the bounds of the ArrayList");
} else if (index2 < 0 || index2 >= scores.size()) {
throw new IndexOutOfBoundsException(index2
+ " is outside the bounds of the ArrayList");
} else {
return scores.get(index1) + scores.get(index2);
}
}
When to Throw an Exception
- Your program should only throw exceptions for exceptional conditions
- This may happen when a method encounters a situation where it cannot complete its task
- For example: the wrong file name was passed to the method opening a file
- Throw an exception to the calling method, which can ask the user for the correct name
* Inserts a new element at the specified
* index in the list array.
* Resizes the list array if it is
* at capacity before inserting
* @param index the index at which to insert
* @param str the element to insert
*/
public void add(int index, E element)
{
if (index >= numElements) {
System.out.println("Error: Cannot add element " + element
+ " at index " + index + ".\nIndex is "
+ "outside the bounds of the array list."
+ "\nIndex: " + index + ", Size: " + numElements);
return;
} else if (atCapacity()) {
reSize();
}
for (int i = numElements; i > index; i--) {
array[i] = array[i-1];
}
array[index] = element;
numElements++;
}
Activity 16.2: More Scores (10 pts)
if (index >= numElements) {
System.out.println("Error: Cannot add element " + element
+ " at index " + index + ".\nIndex is "
+ "outside the bounds of the array list."
+ "\nIndex: " + index + ", Size: " + numElements);
return;
} else if (atCapacity()) {
reSize();
}
for (int i = numElements; i > index; i--) {
array[i] = array[i-1];
}
array[index] = element;
numElements++;
}
Activity 16.2: More Scores (10 pts)
- Open up your Scores.java from last activity and copy and paste the following code into it:
/**
* Scores.java
* @author
* CIS 36B, Activity 16.2
*/
import java.util.Scanner;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
public class Scores {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<Double> scores = new ArrayList<Double>();
String fileName;
boolean more = true;
System.out.println("Welcome!\n");
fileName = input.next();
readScoresFromFile(scores, fileName);
input.close();
System.out.println("\nScores Summary:");
System.out.println("\nSum of scores: " + computeSum(scores));
System.out.println("Number of scores: " + scores.size());
System.out.println("Average: " + (computeSum(scores) / scores.size()));
input.close();
}
public static void readScoresFromFile
(ArrayList<Double> scores, String fileName) {
File file = new File(fileName);
Scanner input = new Scanner(file);
while(input.hasNextDouble()) {
scores.add(input.nextDouble());
}
input.close();
}
public static double computeSum(ArrayList<Double> scores) {
double sum = 0.0;
for (int i = 0; i < scores.size(); i++) {
sum += scores.get(i);
}
return sum;
}
}
* Scores.java
* @author
* CIS 36B, Activity 16.2
*/
import java.util.Scanner;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
public class Scores {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<Double> scores = new ArrayList<Double>();
String fileName;
boolean more = true;
System.out.println("Welcome!\n");
fileName = input.next();
readScoresFromFile(scores, fileName);
input.close();
System.out.println("\nScores Summary:");
System.out.println("\nSum of scores: " + computeSum(scores));
System.out.println("Number of scores: " + scores.size());
System.out.println("Average: " + (computeSum(scores) / scores.size()));
input.close();
}
public static void readScoresFromFile
(ArrayList<Double> scores, String fileName) {
File file = new File(fileName);
Scanner input = new Scanner(file);
while(input.hasNextDouble()) {
scores.add(input.nextDouble());
}
input.close();
}
public static double computeSum(ArrayList<Double> scores) {
double sum = 0.0;
for (int i = 0; i < scores.size(); i++) {
sum += scores.get(i);
}
return sum;
}
}
- Next, create a file inside the same project folder in Eclipse.
- The file should be named scores.txt
- Copy and paste the below contents into scores.txt:
60
70
80
90
100
70
80
90
100
- Notice that Scores.java will not compile.
- You are required to throw an IOException because it is a checked exception
- The compiler checks whether the appropriate method in your program throws the exception.
- Note that unchecked exceptions are checked at runtime.
- Thus, your code will compile if you do not throw the unchecked exception.
- Instead, you will see the error when the code runs.
- Fix the readScoresFromFile method so that it throws an IOException
- Then, notice that a new error appears stating that the exception is not handled.
- We will handle the exception in main where the name of the file is input.
- Our goal is to allow the user the opportunity to try again when an incorrect file name is entered.
- Thus, alter main to look like the following:
- Test out the updated main method by entering in the names of some files.
- Verify that the program is working properly as shown below:
Welcome!
Enter the name of a file: scores
Invalid file name.
Enter the name of a file: scores.tx
Invalid file name.
Enter the name of a file: scores.txt
Scores Summary:
Sum of scores: 400.0
Number of scores: 5
Average: 80.0
- When your program is working as shown, submit Scores.java to Canvas.