Quiz yourself: Methods that throw an exception (intermediate)

Understanding the checked exception mechanism requires that you understand how to declare a method that throws a checked exception, and how that differs from a method that either does not throw any exceptions or throws only unchecked ones.

July 6, 2020 | Download a PDF of this article
More quiz questions available here

If you have worked on our quiz questions in the past, you know none of them is easy. They model the difficult questions from certification examinations. The “intermediate” and “advanced” designations refer to the exams rather than to the questions, although in almost all cases, “advanced” questions will be harder. We write questions for the certification exams, and we intend that the same rules apply: Take words at their face value and trust that the questions are not intended to deceive you but to straightforwardly test your knowledge of the ins and outs of the language.

In this intermediate-level Java SE 11 quiz, the objective is to create and invoke a method that throws an exception.

Given the following class:


public class FileProcessor {
	public static void main(String[] args) {
		try {
			read();			
			write();
		} catch (IOException e) {
			System.out.print("E");
		} finally {
			System.out.print("F");
		}		
	}	
	private static void read() throws Exception {
		System.out.print("R");		
		throw new FileNotFoundException();	
	}	
	private static void write() {
		if (true) {
			throw new RuntimeException();
		}
		System.out.print("W");
	}
}

What is the result? Choose one.

A. The code prints REF.
B. Compilation of the main() method fails.
C. Compilation of the read() method fails.
D. Compilation of the write() method fails.
 

Answer. This question investigates the checked exception mechanism and requires that you understand how to declare a method that throws a checked exception. You also have to understand how that differs from a method that either does not throw any exceptions or throws only unchecked ones.

Let’s review the options in the reverse order.

Option D suggests there’s a problem with the method write(). Two potential concerns might make you wonder about this. One is that the method throws an exception, but that exception isn’t included in a throws clause on the method’s declaration. However, because RuntimeException is one of the main exceptions in the unchecked category, the compiler doesn’t care about it at all, and that aspect is not a problem.

The second potential problem to consider is that the compiler has a tendency to complain if it determines that code is unreachable—that is, if it’s impossible for the code ever to execute. For example, in the following variation on the write method, it’s impossible for the System.out.print call ever to execute, and this would cause a compilation error:


private static void write() {
	throw new RuntimeException();
	System.out.print("W"); // fails to compile; line is never reached
}

However, it turns out that if you make the throw appear to be conditional using the if construct, the compiler will not complain. This is the case even if a hardcoded true value is used; as a human, you know the code below it is unreachable, but the compiler is fairly shortsighted and doesn’t notice. So, there are, in fact, no problems with the write method implemented in the question, and option D is incorrect.

Option C also investigates a method that throws an exception. In this case, the method actually throws a java.io.FileNotFoundException but the method declares that it may throw a different exception, specifically java.lang.Exception. However, since FileNotFoundException is a subclass of Exception, the code is valid and option C is incorrect. After all, since a FileNotFoundException is an Exception, no surprises can occur at the caller. Note that swapping the type thrown and the declaration would be invalid, so the following would not compile:


private static void read() throws FileNotFoundException {
	System.out.print("R");		
	throw new Exception(); // fails to compile; broader than declared
}	

Now let’s look at option B. The main() method contains a try block that calls two methods and is supported by a catch that is ready to handle any IOException or subtype thereof. However, the read() method declares that it might throw an Exception. Given that the compiler believes exceptions might arise from read() that are not caught by the given catch block, one of two things would be necessary for this code to compile. Either the catch handling must be made broader (either by adding another catch or by changing the type in the existing catch), or the main() method must be declared to throw that broader exception. Since neither of these is present in the provided code, you know that the main method cannot compile, and thus option B is correct.

How about option A? You might think that at runtime, the read() method only ever throws FileNotFoundException and this should make the code acceptable. However, the declaration on the read() method would allow that method to be modified, or perhaps overridden in a subclass, later to throw more exceptions than in the original form. When that happens, the compiler will not check all the calls to the method. (Indeed, it’s likely for libraries that such calls might not even be on the same machine performing the compilation.) Consequently, the compiler requires that the call site either declare or handle all the exceptions declared on a called method, without regard to whether they are actually possible at the time of compilation.

Since the code does not compile, it cannot produce any output, and option A must be incorrect. The code would have printed REF if the code had properly matched throws and catch blocks, such as in this code:


public static void main(String[] args) {
	try {
		read();			
		write();
	} catch (IOException e) {
		System.out.print("E");
	} finally {
		System.out.print("F");
	}		
}	
private static void read() throws FileNotFoundException {
	System.out.print("R");		
	throw new FileNotFoundException();	
}

The correct answer is option B, because the code will not compile due to a problem in the main() method.

Simon Roberts

Simon Roberts joined Sun Microsystems in time to teach Sun’s first Java classes in the UK. He created the Sun Certified Java Programmer and Sun Certified Java Developer exams. He wrote several Java certification guides and is currently a freelance educator who publishes recorded and live video training through Pearson InformIT (available direct and through the O’Reilly Safari Books Online service). He remains involved with Oracle’s Java certification projects.

Mikalai Zaikin

Mikalai Zaikin is a lead Java developer at IBA IT Park in Minsk, Belarus. During his career, he has helped Oracle with development of Java certification exams, and he has been a technical reviewer of several Java certification books, including three editions of the famous Sun Certified Programmer for Java study guides by Kathy Sierra and Bert Bates.

Share this Page