3.10. Additional Practice Exercises¶
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.
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 callsrun()on line4.run()callsprocessText(null)on line8.processText()tries to use.length()on a null string on line12which leads to aNullPointerException
Further Explanation:
The last line (D) in the stack trace shows where the
program began. 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.
A NullPointerException in Java means you tried to use an object
reference that is null. In other words, you’re trying to call a
method or access a field on an object that doesn’t exist in
memory.
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
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
NullPointerExceptionwhen we calltoUpperCaseon variableuserInputwhich containsnull.Where will the exception originate?
Solution
The
NullPointerExceptionoriginates on line 4.Since
maindoes not catch the exception, it propagates outside ofmainand crashes the program. Exceptions move up the call stack through calling methods until handled or the program stops.Without using an
ifstatement, rewrite the program so that it prints “Encountered a null value” and then continues.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
Predict what exception will be thrown, where, and why.
Solution
names[1]was never initialized, so it isnull. When we passnames[1]tocheckName, it attempts to calllength()on anullreference. So, ANullPointerExceptionwill originate on line 31.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 crash in two main ways:
nameisnull→ causes aNullPointerExceptionwhen callingname.length().scoresisnullor has length0→ causes aNullPointerExceptionorArrayIndexOutOfBoundsExceptionwhen accessingscores[0].
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) - Ifstris not a valid integer (e.g., “apple”, “3.14”, “”, null).Integer.parseInt()expects a well-formed integer string.ArithmeticException- ifvalueis0which would cause a divide by zero.NullPointerException(NPE) - if theinputitself isnull.
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
1This is the output of our code:
2
3.. code-block::
4
5 Exception in thread "main" java.lang.NumberFormatException: For input string: "3.14"
6 at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
7 at java.base/java.lang.Integer.parseInt(Integer.java:668)
8 at java.base/java.lang.Integer.parseInt(Integer.java:786)
9 at DataParser.parseAndDivide(DataParser.java:9)
10 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
1The output is:
2
3.. code-block::
4
5 Invalid integer input: 3.14
6 100 / 50 = 2
7 100 / 200 = 0
8 Input array reference cannot be null
9 100 / 200 = 0
10 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);
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
nis declared inside thetryblock and is not visible outside. The lineSystem.out.println("The value of n is: " + n);tries to accessnout of scope, where it doesn’t exist.Refactor the code using two different strategies to fix it:
Using strategy 1 (move dependent code inside the
tryblock).Using strategy 2 (extend the scope by declaring outside the
tryblock 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
Which strategy (1 or 2) is preferred? Why?
Question 9
Explain the difference between a checked and an unchecked exception in Java.
Solution
Checked exceptions are exceptions that the compiler requires you to handle either with a try-catch block or by declaring them with
throws. Examples includeIOExceptionandFileNotFoundException.Unchecked exceptions are exceptions that the compiler does not require you to handle. They usually indicate programming errors, such as
NullPointerExceptionorArrayIndexOutOfBoundsException. These are subclasses ofRuntimeException.Identify which of the two programs below will not compile.
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
ArrayIndexOutOfBoundsExceptionat 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
FileNotFoundExceptionis a checked exception, the compiler enforces handling it with a try-catch or throws.