3.10. Additional Practice Exercises

3.10.1. Exception Analysis

Exception Analysis

To see sample solutions, toggle "Show Solutions" above.

Sample solutions not included, because "Show Solutions" was not toggled before printing.

Question 1

Given only the following stack trace, explain what each line of the trace reveals about the method call hierarchy and the exception type. Line A is wrapped here for readability.

A. | Exception in thread "main" java.lang.NullPointerException:
   | Cannot invoke "String.length()" because "text" is null
B. |   at SimpleExample.processText(SimpleExample.java:12)
C. |   at SimpleExample.run(SimpleExample.java:8)
D. |   at SimpleExample.main(SimpleExample.java:4)
Solution

The method call chain shows:

  • The program starts in main(), which calls run() on line 4.

  • run() calls processText on line 8. The trace does not reveal the argument expression used in that call.

  • processText() calls length() when the value of text is null on line 12, causing a NullPointerException.

Further Explanation:

The last line (D) shows the earliest method call represented in this trace. In this scenario, the program began in the main method which ran to line 4 of SimpleExample.java. On line 4, the program called the run method which ran to line 8 of our code (seen in line C). The run method called processText on line 8 and processText ran to line 12 which is where the NullPointerException originated.

Here, the value of text is null, which means it does not refer to an object. Invoking an instance method through that value causes NullPointerException.

Question 2

Given only the following stack trace, explain what each line of the trace reveals about the method call hierarchy and the exception type.

Exception in thread "main" java.lang.IllegalArgumentException: Invalid input
   at QuizApp.scoreAnswer(QuizApp.java:32)
   at QuizApp.gradeQuiz(QuizApp.java:18)
   at QuizApp.main(QuizApp.java:7)
Solution

This code throws an IllegalArgumentException. You should attempt to explain the output in a manner consistent with the previous question.

Question 3

Consider the following simple Java program:

 1/**
 2 * Example program demonstrating string operations.
 3 */
 4public class Example {
 5
 6   /**
 7    * The main entry point of the program.
 8    *
 9    * @param args command-line arguments (not used)
10    */
11   public static void main(String[] args) {
12      String userInput = null;
13      System.out.println("You entered: " + userInput.toUpperCase());
14      System.out.println("Program continues...");
15   } // main
16
17} // Example
  1. Do you anticipate this code will run successfully? If not, explain what kind of error will occur, and why.

    Solution

    The code will not run successfully. There will be a runtime error NullPointerException when we call toUpperCase on variable userInput which contains null.

    Since main does not catch the exception, it propagates outside of main and crashes the program. Exceptions move up the call stack through calling methods until handled or the program stops.

  2. Without using an if statement, rewrite the program so that it prints "Encountered a null value" and then continues.

    Solution
    Listing 3.4 One Possible Solution
     1/**
     2* Example program demonstrating exception handling with NullPointerException.
     3*/
     4public class Example {
     5
     6   /**
     7   * The main entry point of the program.
     8   *
     9   * @param args command-line arguments (not used)
    10   */
    11   public static void main(String[] args) {
    12      String userInput = null;
    13
    14      try {
    15            System.out.println("You entered: " + userInput.toUpperCase());
    16      } catch (NullPointerException e) {
    17            System.out.println("Encountered a null value");
    18      } // try
    19
    20      System.out.println("Program continues...");
    21   } // main
    22
    23} // Example
    
Question 4

Consider the following code:

 1/**
 2* Mystery program demonstrating when exceptions may occur.
 3*/
 4public class Mystery {
 5
 6   /**
 7   * The main entry point of the program.
 8   *
 9   * @param args command-line arguments (not used)
10   */
11   public static void main(String[] args) {
12      new Mystery().start();
13   } // main
14
15   /**
16   * Starts the program by initializing an array and checking a name.
17   */
18   public void start() {
19      String[] names = new String[3];
20      names[0] = "Aisha";
21      names[2] = "Chen";
22      checkName(names[1]);
23   } // start
24
25   /**
26   * Checks if the provided name is valid.
27   *
28   * @param name the name to check
29   */
30   public void checkName(String name) {
31      if (name.length() > 0) {
32            System.out.println("Valid name!");
33      } // if
34   } // checkName
35
36} // Mystery
  1. Predict what exception will be thrown, where, and why.

    Solution

    Array components of reference type are initialized to null. No subsequent assignment changed the value of names[1]. When we pass names[1] to checkName, it attempts to call length() when the value of name is null. A NullPointerException originates at that method call.

  2. Using a try-catch, how could you modify the code to avoid the crash?

    One Possible Solution
     1/**
     2* Checks whether the given name is valid.
     3*
     4* @param name the string to check
     5*/
     6public void checkName(String name) {
     7   try {
     8      if (name.length() > 0) {
     9         System.out.println("Valid name!");
    10      } // if
    11   } catch (NullPointerException npe) {
    12      System.out.println("Invalid name");
    13   } // try
    14} // checkName
    
Question 5

Identify two ways the following method could crash:

 1/**
 2* Determines if a student is eligible based on their name and scores.
 3*
 4* @param name   the student's name
 5* @param scores array of scores
 6* @return true if the name length is greater than 3 and the first score is above 70
 7*/
 8public static boolean isEligible(String name, int[] scores) {
 9   return name.length() > 3 && scores[0] > 70;
10} //isEligible
Solution

This method can complete abruptly in these cases:

  1. name is null → causes a NullPointerException when calling name.length().

  2. When name.length() > 3 is true, scores[0] is evaluated. If scores is null, this causes NullPointerException; if its length is zero, this causes ArrayIndexOutOfBoundsException. Otherwise, short-circuit evaluation skips this array access.

Question 6

Consider the following DataParser class that defines a method called parseAndDivide which accepts an array of strings, iterates over each string and parses it into an integer. It further divides 100 by the parsed integer and prints out the result.

List at least two things that could go wrong in the code below.

Note: You may need to look up method(s) to see which exceptions they throw (if any).

 1/**
 2 * Provides utility methods to parse strings and perform division.
 3 */
 4public class DataParser {
 5
 6   /**
 7   * Parses each string in the input array as an integer and divides 100 by it.
 8   *
 9   * @param input an array of strings representing integers
10   */
11   public static void parseAndDivide(String[] input) {
12      for (String str : input) {
13         int value = Integer.parseInt(str);
14         int result = 100 / value;
15         System.out.println("100 / " + value + " = " + result);
16      } // for
17   } // parseAndDivide
18
19} // DataParser
Solution

We could get the following exceptions:

  • NumberFormatException (NFE) - If str is not a valid integer (e.g., "apple", "3.14", "", null). Integer.parseInt() expects a well-formed integer string.

  • ArithmeticException - if value is 0 which would cause a divide by zero.

  • NullPointerException (NPE) - if the input itself is null.

Question 7
A. What is the output of the code below?

Note: This is an updated version of the DataParser class from the previous question.

 1public class DataParser {
 2    public static void parseAndDivide(String[] input) {
 3
 4        try {
 5            for (int i = 0; i < input.length; i++) {
 6                String str = input[i];
 7                try {
 8                    int value = Integer.parseInt(str);   // may throw NumberFormatException
 9                    int result = 100 / value;            // may throw ArithmeticException
10                    System.out.println("100 / " + value + " = " + result);
11                } catch (ArithmeticException e) {
12                    System.out.println("Cannot divide by zero: " + str);
13                } catch (NullPointerException e) {
14                    System.out.println("Array elements cannot be null");
15                } // try
16            } // for
17        } catch (NullPointerException npe) {
18            System.out.println("Input array reference cannot be null");
19        } // try
20
21    } // parseAndDivide
22
23    public static void main(String[] args) {
24
25        String[] input1 = new String[] {"3.14", "50", "200"};
26        String[] input2 = null;
27        String[] input3 = new String[] {"200", null};
28
29        DataParser.parseAndDivide(input1);
30        DataParser.parseAndDivide(input2);
31        DataParser.parseAndDivide(input3);
32
33    } // main
34} // DataParser
Solution

The first call throws an uncaught NumberFormatException. Later calls in main are not reached. JDK frame line numbers vary by version; the trace has this form:

Exception in thread "main" java.lang.NumberFormatException: For input string: "3.14"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:...)
    at java.base/java.lang.Integer.parseInt(Integer.java:...)
    at java.base/java.lang.Integer.parseInt(Integer.java:...)
    at DataParser.parseAndDivide(DataParser.java:9)
    at DataParser.main(DataParser.java:30)
B. Explain

In part A, we added try-catch statements, but the code still crashed. Why? How can we fix it?

See if you can fix the code before moving on.

Solution

The code crashed because Integer.parseInt threw a NumberFormatException that was never caught. That exception propagated out of main and crashed the program as we saw in the stack trace.

To fix this, we need to add another catch statement to our code.

C. What is the output of the updated code below?

Note: This is an updated version of the DataParser class from the previous question.

 1public class DataParser {
 2    public static void parseAndDivide(String[] input) {
 3
 4        try {
 5            for (int i = 0; i < input.length; i++) {
 6                String str = input[i];
 7                try {
 8                    int value = Integer.parseInt(str);   // may throw NumberFormatException
 9                    int result = 100 / value;            // may throw ArithmeticException
10                    System.out.println("100 / " + value + " = " + result);
11                } catch (NumberFormatException e) {
12                    System.out.println("Invalid integer input: " + str);
13                } catch (ArithmeticException e) {
14                    System.out.println("Cannot divide by zero: " + str);
15                } catch (NullPointerException e) {
16                    System.out.println("Array elements cannot be null");
17                } // try
18            } // for
19        } catch (NullPointerException npe) {
20            System.out.println("Input array reference cannot be null");
21        } // try
22
23    } // parseAndDivide
24
25    public static void main(String[] args) {
26
27        String[] input1 = new String[] {"3.14", "50", "200"};
28        String[] input2 = null;
29        String[] input3 = new String[] {"200", null};
30
31        DataParser.parseAndDivide(input1);
32        DataParser.parseAndDivide(input2);
33        DataParser.parseAndDivide(input3);
34
35    } // main
36} // DataParser
Solution

The output is:

Invalid integer input: 3.14
100 / 50 = 2
100 / 200 = 0
Input array reference cannot be null
100 / 200 = 0
Invalid integer input: null
Question 8

Take a few moments to review the code below:

1try {
2   int n = Integer.parseInt(args[0]);
3} catch (NumberFormatException e) {
4   System.out.println("Invalid number");
5} // try
6
7System.out.println("The value of n is: " + n);
  1. Why won't this code compile?

    Solution

    This is a compile-time error related to scoping. See section 3.6 ("Regarding Scope") for more examples.

    The variable n is declared inside the try block and is not visible outside. The line System.out.println("The value of n is: " + n); tries to access n out of scope, where it doesn't exist.

  2. Refactor the code using two different strategies to fix it:

    • Using strategy 1 (move dependent code inside the try block).

    • Using strategy 2 (extend the scope by declaring outside the try block but safely handle exceptions after the block.)

    Solution

    Strategy 1:

    1try {
    2   int n = Integer.parseInt(args[0]);
    3   System.out.println("The value of n is: " + n);
    4} catch (NumberFormatException e) {
    5   System.out.println("Invalid number");
    6} // try
    

    Strategy 2:

     1int n = 0;
     2boolean success = false;
     3
     4try {
     5   n = Integer.parseInt(args[0]);
     6   success = true;
     7} catch (NumberFormatException e) {
     8   System.out.println("Invalid number");
     9} // try
    10if (success) {
    11   System.out.println("The value of n is: " + n);
    12} // if
    
  3. Which strategy (1 or 2) is preferred? Why?

    Solution

    Prefer strategy 1 here: it keeps the dependent statement with the operation that produces its value and needs no success flag. Strategy 2 is useful when later code needs the variable, but that code must account for failure to obtain a value.

Question 9
  1. Explain the difference between a checked and an unchecked exception in Java.

    Solution

    Checked exceptions are exceptions that the compiler requires you to catch or declare with throws when they can escape a method. Examples include IOException and FileNotFoundException.

    Unchecked exceptions are exceptions that the compiler does not require you to handle. They usually indicate programming errors, such as NullPointerException or ArrayIndexOutOfBoundsException. These examples are subclasses of RuntimeException. The unchecked exception classes also include Error and its subclasses; all other exception classes are checked.

  2. Identify which of the two programs below will not compile.

    Code Snippet A:

    Listing 3.5 Code Snippet A
    1int[] numbers = {1, 2, 3};
    2System.out.println(numbers[5]); // ArrayIndexOutOfBoundsException
    

    Code Snippet B:

    1File file = new File("notes.txt");
    2Scanner scanner = new Scanner(file);  // FileNotFoundException
    3System.out.println(scanner.nextLine());
    
    Solution

    Code Snippet A will compile successfully but will throw an ArrayIndexOutOfBoundsException at runtime. This is an unchecked exception. Java does not require you to handle it at compile time.

    Code Snippet B will fail to compile unless you handle or declare the exception. Because FileNotFoundException is a checked exception, the compiler enforces handling it with a try-catch or throws.

3.10.2. Parsons Problems

Parsons Problems

To see sample solutions, toggle "Show Solutions" above.

Sample solutions not included, because "Show Solutions" was not toggled before printing.

Practice the exception-handling patterns from this chapter. Each problem is independent. Some ask for a complete method; others provide a method signature and ask only for its body. Assume methods belong to an enclosing class. Review Handling Exceptions (Try-Catch), Regarding Scope, and Explicitly Throwing Exceptions & Exception Propagation as needed.

Use every correct block once and leave the incorrect block unused. Arrange blocks vertically and set their indentation. Level zero is the left edge of the requested fragment; each additional level represents four spaces. For method-body fragments, add the enclosing method's indentation when inserting the fragment into a class. Preserve relative indentation within each block.

Use the interactive controls or open a text version to work on paper or without JavaScript. Letters identify whole blocks. Sample solutions are available by opening their dropdowns. Use Show Solutions to hide or show those dropdowns, including when printing.

Problem 1: Guard before dereferencing

Construct nameLength. Return with zero when name is null; otherwise return with its length. Check for null before invoking an instance method.

Unused Blocks
Solution Construction

Text version of Problem 1

Construct nameLength. Return with zero when name is null; otherwise return with its length. Check for null before invoking an instance method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

if (name == null) {

Block B

public static int nameLength(String name) {

Block C

return 0;

Block D

return name.length();

Block E

} // if

Block F

} // nameLength

Block G

if (name.equals(null)) {
Text version of Problem 1

Construct nameLength. Return with zero when name is null; otherwise return with its length. Check for null before invoking an instance method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

if (name == null) {

Block B

public static int nameLength(String name) {

Block C

return 0;

Block D

return name.length();

Block E

} // if

Block F

} // nameLength

Block G

if (name.equals(null)) {
Sample solution for Problem 1

Block order: B, A, C, E, D, F.

Indentation levels: 0, 1, 2, 1, 1, 0.

public static int nameLength(String name) {
    if (name == null) {
        return 0;
    } // if
    return name.length();
} // nameLength

The guard compares the reference value with null without dereferencing it. The early return prevents the later method call when name does not refer to an object. Calling name.equals(null) cannot perform this guard: it throws NullPointerException when the value of name is null.

Problem 2: Catch and continue

Construct the body of public static void printNumber(String text). Print the parsed integer, or print Invalid integer if parsing throws NumberFormatException. Then print Done in either case. The argument may be null.

Unused Blocks
Solution Construction

Text version of Problem 2

Construct the body of public static void printNumber(String text). Print the parsed integer, or print Invalid integer if parsing throws NumberFormatException. Then print Done in either case. The argument may be null.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println("Done");

Block B

} // try

Block C

System.out.println(Integer.parseInt(text));

Block D

try {

Block E

System.out.println("Invalid integer");

Block F

} catch (NumberFormatException e) {

Block G

} catch (NullPointerException e) {
Text version of Problem 2

Construct the body of public static void printNumber(String text). Print the parsed integer, or print Invalid integer if parsing throws NumberFormatException. Then print Done in either case. The argument may be null.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println("Done");

Block B

} // try

Block C

System.out.println(Integer.parseInt(text));

Block D

try {

Block E

System.out.println("Invalid integer");

Block F

} catch (NumberFormatException e) {

Block G

} catch (NullPointerException e) {
Sample solution for Problem 2

Block order: D, C, F, E, B, A.

Indentation levels: 0, 1, 0, 1, 0, 0.

try {
    System.out.println(Integer.parseInt(text));
} catch (NumberFormatException e) {
    System.out.println("Invalid integer");
} // try
System.out.println("Done");

Normal parsing skips the handler. A parsing failure enters the NumberFormatException handler, after which execution continues with Done. Even a null argument to Integer.parseInt causes NumberFormatException; a NullPointerException handler would not catch it.

Problem 3: Use a parsed value within its scope

Construct the body of public static void printNext(String text). Parse text into a local variable n, then print n + 1 only if parsing succeeds. Otherwise print No number. Valid input represents an integer smaller than Integer.MAX_VALUE.

Unused Blocks
Solution Construction

Text version of Problem 3

Construct the body of public static void printNext(String text). Parse text into a local variable n, then print n + 1 only if parsing succeeds. Otherwise print No number. Valid input represents an integer smaller than Integer.MAX_VALUE.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

try {

Block B

System.out.println("No number");

Block C

} // try

Block D

System.out.println(n + 1);

Block E

System.out.println(n + 1);

Block F

} catch (NumberFormatException e) {

Block G

int n = Integer.parseInt(text);
Text version of Problem 3

Construct the body of public static void printNext(String text). Parse text into a local variable n, then print n + 1 only if parsing succeeds. Otherwise print No number. Valid input represents an integer smaller than Integer.MAX_VALUE.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

try {

Block B

System.out.println("No number");

Block C

} // try

Block D

System.out.println(n + 1);

Block E

System.out.println(n + 1);

Block F

} catch (NumberFormatException e) {

Block G

int n = Integer.parseInt(text);
Sample solution for Problem 3

Block order: A, G, D, F, B, C.

Indentation levels: 0, 1, 1, 0, 1, 0.

try {
    int n = Integer.parseInt(text);
    System.out.println(n + 1);
} catch (NumberFormatException e) {
    System.out.println("No number");
} // try

The declaration and dependent output belong in the same try block. If parsing fails, execution skips the dependent output. The catch block is a separate scope: using n there is a compile-time error, even though the declaration appears earlier in the source.

Problem 4: Distinguish parsing and arithmetic failures

Construct the body of public static void divide(String text). Parse text into value and print the integer quotient 100 / value. Print Invalid integer for a parsing failure and Zero divisor for division by zero. Use separate handlers; either order of the two handlers is acceptable.

Unused Blocks
Solution Construction

Text version of Problem 4

Construct the body of public static void divide(String text). Parse text into value and print the integer quotient 100 / value. Print Invalid integer for a parsing failure and Zero divisor for division by zero. Use separate handlers; either order of the two handlers is acceptable.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println(100 / value);

Block B

int value = Integer.parseInt(text);

Block C

} catch (ArithmeticException e) {
    System.out.println("Invalid integer");

Block D

try {

Block E

} catch (ArithmeticException e) {
    System.out.println("Zero divisor");

Block F

} catch (NumberFormatException e) {
    System.out.println("Invalid integer");

Block G

} // try
Text version of Problem 4

Construct the body of public static void divide(String text). Parse text into value and print the integer quotient 100 / value. Print Invalid integer for a parsing failure and Zero divisor for division by zero. Use separate handlers; either order of the two handlers is acceptable.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println(100 / value);

Block B

int value = Integer.parseInt(text);

Block C

} catch (ArithmeticException e) {
    System.out.println("Invalid integer");

Block D

try {

Block E

} catch (ArithmeticException e) {
    System.out.println("Zero divisor");

Block F

} catch (NumberFormatException e) {
    System.out.println("Invalid integer");

Block G

} // try
Sample solution for Problem 4

Block order: D, B, A, F, E, G.

Indentation levels: 0, 1, 1, 0, 0, 0.

try {
    int value = Integer.parseInt(text);
    System.out.println(100 / value);
} catch (NumberFormatException e) {
    System.out.println("Invalid integer");
} catch (ArithmeticException e) {
    System.out.println("Zero divisor");
} // try

Other accepted arrangements may also be valid.

Parsing and integer division can fail for different reasons, so each handler reports its own failure. Only the matching handler runs. These exception classes are unrelated by inheritance, so reversing the handlers preserves behavior. The distractor catches division by zero but reports the wrong cause.

Problem 5: Recover for each input

Construct the body of public static void printNumbers(String[] input). Assume input is not null. Process its elements in order, printing each parsed integer or Invalid integer for an element that cannot be parsed. Continue with later elements after a failure, including when an element is null.

Unused Blocks
Solution Construction

Text version of Problem 5

Construct the body of public static void printNumbers(String[] input). Assume input is not null. Process its elements in order, printing each parsed integer or Invalid integer for an element that cannot be parsed. Continue with later elements after a failure, including when an element is null.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

for (String text : input) {

Block B

} // try

Block C

try {

Block D

} // for

Block E

} catch (NumberFormatException e) {

Block F

System.out.println("Invalid integer");

Block G

System.out.println("Invalid integer");
return;

Block H

System.out.println(Integer.parseInt(text));
Text version of Problem 5

Construct the body of public static void printNumbers(String[] input). Assume input is not null. Process its elements in order, printing each parsed integer or Invalid integer for an element that cannot be parsed. Continue with later elements after a failure, including when an element is null.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

for (String text : input) {

Block B

} // try

Block C

try {

Block D

} // for

Block E

} catch (NumberFormatException e) {

Block F

System.out.println("Invalid integer");

Block G

System.out.println("Invalid integer");
return;

Block H

System.out.println(Integer.parseInt(text));
Sample solution for Problem 5

Block order: A, C, H, E, F, B, D.

Indentation levels: 0, 1, 2, 1, 2, 1, 0.

for (String text : input) {
    try {
        System.out.println(Integer.parseInt(text));
    } catch (NumberFormatException e) {
        System.out.println("Invalid integer");
    } // try
} // for

Placing the try-catch inside the loop gives each element its own recovery path. After the handler finishes, the next iteration can begin. The distractor reports the failure but returns from the entire method; it prevents later elements from being processed.

Problem 6: Reject an invalid argument

Construct requirePositive. Throw IllegalArgumentException with message count must be positive if count is zero or negative. Otherwise return with count. Do not catch the exception in this method.

Unused Blocks
Solution Construction

Text version of Problem 6

Construct requirePositive. Throw IllegalArgumentException with message count must be positive if count is zero or negative. Otherwise return with count. Do not catch the exception in this method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

} // requirePositive

Block B

public static int requirePositive(int count) {

Block C

throw new IllegalArgumentException("count must be positive");

Block D

return count;

Block E

if (count <= 0) {

Block F

} // if

Block G

new IllegalArgumentException("count must be positive");
Text version of Problem 6

Construct requirePositive. Throw IllegalArgumentException with message count must be positive if count is zero or negative. Otherwise return with count. Do not catch the exception in this method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

} // requirePositive

Block B

public static int requirePositive(int count) {

Block C

throw new IllegalArgumentException("count must be positive");

Block D

return count;

Block E

if (count <= 0) {

Block F

} // if

Block G

new IllegalArgumentException("count must be positive");
Sample solution for Problem 6

Block order: B, E, C, F, D, A.

Indentation levels: 0, 1, 2, 1, 1, 0.

public static int requirePositive(int count) {
    if (count <= 0) {
        throw new IllegalArgumentException("count must be positive");
    } // if
    return count;
} // requirePositive

The guard rejects both zero and negative values. The throw statement completes this method abruptly, so rejected values never reach the return statement. Allocating an exception object alone does not throw it. Because IllegalArgumentException is unchecked, a throws clause is not required.

Problem 7: Handle a checked exception

Assume the enclosing class already defines static int readScore(String filename) throws FileNotFoundException. It returns with an integer score from a file or throws FileNotFoundException when the file cannot be opened. For these exercises, assume no other failures. Import java.io.FileNotFoundException.

Construct the body of public static void printScore(String filename). Print the score returned by readScore(filename). If the file cannot be opened, print Missing file. Handle the checked exception within this method.

Unused Blocks
Solution Construction

Text version of Problem 7

Construct the body of public static void printScore(String filename). Print the score returned by readScore(filename). If the file cannot be opened, print Missing file. Handle the checked exception within this method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println("Missing file");

Block B

try {

Block C

} catch (RuntimeException e) {

Block D

int score = readScore(filename);

Block E

System.out.println(score);

Block F

} // try

Block G

} catch (FileNotFoundException e) {
Text version of Problem 7

Construct the body of public static void printScore(String filename). Print the score returned by readScore(filename). If the file cannot be opened, print Missing file. Handle the checked exception within this method.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

System.out.println("Missing file");

Block B

try {

Block C

} catch (RuntimeException e) {

Block D

int score = readScore(filename);

Block E

System.out.println(score);

Block F

} // try

Block G

} catch (FileNotFoundException e) {
Sample solution for Problem 7

Block order: B, D, E, G, A, F.

Indentation levels: 0, 1, 1, 0, 1, 0.

try {
    int score = readScore(filename);
    System.out.println(score);
} catch (FileNotFoundException e) {
    System.out.println("Missing file");
} // try

The call can throw the checked exception FileNotFoundException. This method catches it and reports the failure. Catching RuntimeException would not satisfy the compiler: it does not cover FileNotFoundException, and this method declares no throws clause.

Problem 8: Propagate to a caller that handles the failure

Assume the enclosing class already defines static int readScore(String filename) throws FileNotFoundException. It returns with an integer score from a file or throws FileNotFoundException when the file cannot be opened. For these exercises, assume no other failures. Import java.io.FileNotFoundException.

The enclosing class also contains this caller:

public static void reportScore(String filename) {
    try {
        System.out.println(loadScore(filename));
    } catch (FileNotFoundException e) {
        System.out.println("Missing file");
    } // try
} // reportScore

Construct loadScore to call readScore(filename), store the result in score, and return with it. Let FileNotFoundException propagate to the supplied caller. Do not catch it or replace a missing score with a default value.

Unused Blocks
Solution Construction

Text version of Problem 8

Construct loadScore to call readScore(filename), store the result in score, and return with it. Let FileNotFoundException propagate to the supplied caller. Do not catch it or replace a missing score with a default value.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

return score;

Block B

} // loadScore

Block C

public static int loadScore(String filename)
    throws FileNotFoundException {

Block D

int score = readScore(filename);

Block E

public static int loadScore(String filename) {
Text version of Problem 8

Construct loadScore to call readScore(filename), store the result in score, and return with it. Let FileNotFoundException propagate to the supplied caller. Do not catch it or replace a missing score with a default value.

Write the letters of the correct blocks in order and give each block an indentation level. Leave incorrect blocks unused and preserve relative indentation within each block.

Block A

return score;

Block B

} // loadScore

Block C

public static int loadScore(String filename)
    throws FileNotFoundException {

Block D

int score = readScore(filename);

Block E

public static int loadScore(String filename) {
Sample solution for Problem 8

Block order: C, D, A, B.

Indentation levels: 0, 1, 1, 0.

public static int loadScore(String filename)
    throws FileNotFoundException {
    int score = readScore(filename);
    return score;
} // loadScore

The throws clause declares a possible checked exception; it does not throw anything by itself. If readScore throws, loadScore propagates that exception and skips its return statement. The supplied caller catches the exception. Omitting the declaration is a compile-time error even though a caller has a handler.