Handle exceptions using try/catch/finally, try-with-resources, and multi-catch blocks, including custom exceptions.
try-with-resources
BlockBeing able to run a program is not the same as running the program correctly. Any non-trivial program is susceptible to errors. Errors in user inputs, mathematical operations, and accessing resources, etc.
That’s where exceptions come into play. An exception indicates some sort of abnormal or exceptional condition that disrupts the normal flow of the program.
When an exceptional condition arises, an exception is said to be thrown. When this happens, the normal flow of the program is disrupted and the execution is transferred to a special block of code called an exception handler, if one exists for the exception.
The purpose of exceptions is to handle these errors gracefully and prevent the program from crashing or behaving unexpectedly. By using exceptions, you can separate the error-handling code from the normal program logic, making your code cleaner and more manageable.
Exceptions don’t necessarily stop the program entirely when they happen. When an exception is thrown, it is propagated up the call stack until it is caught and handled by an exception handler. If no suitable handler is found, the program will terminate. But if you have a try-catch
block in place to handle the exception, your program can deal with the issue and continue running.
Most common exception classes in Java are subtypes of the java.lang.Exception
class. But that’s not the whole story. To really understand exceptions, we need to look at the exception hierarchy:
┌───────────┐
│ Throwable │
└─────┬─────┘
│
┌───────────┴───────────┐
│ │
┌───────────────┐ ┌───────────────┐
│ Exception │ │ Error │
└───────┬───────┘ └───────────────┘
│
┌───────────┴───────────┐
│ │
┌──────────────────┐ ┌───────────────────┐
│ RuntimeException │ │ Checked Exceptions│
└──────────────────┘ └───────────────────┘
At the top of the hierarchy is the java.lang.Throwable
class. Beneath Throwable
are two branches: Exception
and Error
. While they might sound similar, they actually represent quite different things in Java.
Exceptions are conditions that a reasonable application might want to catch and handle. They typically represent conditions that, while unusual, are not entirely unexpected. For example, trying to open a file that doesn’t exist would throw a FileNotFoundException
.
Errors, on the other hand, are not meant to be caught or handled by your program. They indicate serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. For example, if your application runs out of memory, an OutOfMemoryError
will be thrown.
Beneath the Exception
class, there are two further categories: checked exceptions and unchecked exceptions (also known as runtime exceptions because they extend from java.lang.RuntimeException
).
Checked exceptions are exceptional conditions that a well-written application should anticipate and handle. These are typically exceptions that are outside the control of the program, such as a file not being found, a network connection failing, or invalid user input. Checked exceptions are subclasses of Exception
but not RuntimeException
.
Unchecked exceptions are exceptional conditions that the application usually cannot anticipate or recover from. These usually indicate programming bugs, such as logic errors or improper use of an API. Unchecked exceptions are subclasses of RuntimeException
.
While it might seem like unchecked exceptions are sufficient, checked exceptions serve an important purpose. They force the programmer to handle the exception, ensuring that proper error handling code is written. This leads to more robust and reliable code.
On the other hand, unchecked exceptions don’t need to be declared in a method’s throws
clause if they can be thrown by the execution of the method. These usually represent defects in the program (bugs) and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such exceptions most often indicate programming defects, and an unchecked exception is the way the Java programming language allows a developer to indicate a potential defect where the compiler cannot easily detect the problem.
So far, we’ve talked about what exceptions are and the different types of exceptions. But how do exceptions actually get thrown?
An exception can be thrown in two ways: automatically by the Java runtime system, or explicitly by your code.
Many exceptions are thrown automatically by the Java runtime system. For example, if you try to access an array element with an index that is out of bounds, an ArrayIndexOutOfBoundsException
will be thrown. If you try to divide a number by zero, an ArithmeticException
will be thrown.
But you can also throw exceptions explicitly in your code using the throw
statement. The general form of the throw
statement is:
throw new ExceptionType(messageString);
Here, ExceptionType
is the type of exception you want to throw, and messageString
is an optional string that provides more information about the exception.
For example, let’s say you have a method that accepts an integer parameter age. If the passed-in age is negative, you might want to throw an exception:
public void checkAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
// rest of the method
}
In this case, we are throwing an IllegalArgumentException
, which is a type of unchecked exception.
There are many cases where it’s appropriate, and even necessary, for you to throw exceptions in your own code.
By throwing exceptions, you can signal that an error has occurred and provide information about what went wrong. This is especially important when you’re writing methods or classes that will be used by other developers. By throwing exceptions, you can communicate to the user of your code that they have used your method or class incorrectly, or that something has gone wrong that they need to handle.
Moreover, by throwing exceptions, you can separate the error-handling code from the normal flow of your program. This makes your code more readable and maintainable.
While Java provides a rich set of built-in exceptions, there are situations where it can be beneficial to create your own custom exceptions.
Custom exceptions allow you to add more context and meaning to the exceptions thrown by your application. They can help to better encapsulate the error conditions specific to your application domain.
For example, if you’re writing a library for parsing XML files, you might define a custom XMLFileParseException
that you throw whenever there’s an error parsing an XML file. This communicates to the user of your library exactly what went wrong, as opposed to just throwing a generic Exception
.
To create a custom checked exception, you simply need to extend the Exception
class (or one of its subclasses):
public class XMLFileParseException extends Exception {
public XMLFileParseException(String message) {
super(message);
}
}
To create a custom unchecked exception, you extend the RuntimeException
class (or one of its subclasses):
public class InvalidInputException extends RuntimeException {
public InvalidInputException(String message) {
super(message);
}
}
Then you can throw your custom exceptions just like any other exception:
throw new XMLFileParseException("Error parsing XML file: " + fileName);
throw new InvalidInputException("Input cannot be negative");
When deciding whether to make your custom exception checked or unchecked consider the following guidelines:
Use checked exceptions for exceptional conditions that the caller should recover from. These often represent conditions that are outside the control of the program, such as a file not being found or a network connection failing.
Use unchecked exceptions (extending RuntimeException
) for exceptional conditions that the caller usually cannot recover from. These often indicate programming errors, such as trying to access an array element with an out-of-bounds index.
Another thing to consider when creating custom exceptions is serialization. If your exception class is going to be thrown across different JVMs (for example, in a distributed system), it should implement the java.io.Serializable
interface.
public class RemoteServiceException extends Exception implements Serializable {
// ...
}
This ensures that the exception object can be successfully serialized and deserialized when it’s transmitted across the network.
Finally, when creating custom exceptions, it’s a good practice to provide constructors that accept a message string and a cause exception. The cause is the exception that triggered your exception. This allows you to wrap lower-level exceptions in your higher-level custom exceptions, which can provide more context about the error.
public class DataAccessException extends Exception {
public DataAccessException(String message) {
super(message);
}
public DataAccessException(String message, Throwable cause) {
super(message, cause);
}
}
Then you can use it like this:
try {
// some database operation that throws a SQLException
} catch (SQLException ex) {
throw new DataAccessException("Error accessing database", ex);
}
This way, the caller of your code knows that a DataAccessException
occurred, but can still access the underlying cause (the SQLException
) if needed for more detailed error handling or logging.
When a method throws an exception, it must declare this in its method signature. This is done using the throws
keyword followed by a list of the exceptions that the method might throw.
public void readFile(String fileName) throws FileNotFoundException {
// code that might throw a FileNotFoundException
}
In this example, the readFile
method declares that it might throw a FileNotFoundException
.
However, not all exceptions need to be declared in the method signature. Only checked exceptions need to be declared. Unchecked exceptions (those that extend RuntimeException
) do not need to be declared.
This brings us to an important distinction: the difference between throw
and throws
.
throw
is used to actually throw an exception within a method.throws
is used in a method signature to declare that the method might throw an exception.A useful analogy for remembering the difference is a baseball game:
Similarly in Java:
When you override a method in a subclass, you’re allowed to declare that the method throws fewer checked exceptions than the method you’re overriding.
class Parent {
public void doSomething() throws IOException, SQLException {
// ...
}
}
class Child extends Parent {
@Override
public void doSomething() throws IOException {
// ...
}
}
In this example, the doSomething
method in the Parent
class declares that it can throw either an IOException
or a SQLException
. But when we override doSomething
in the Child
class, we declare that it only throws IOException
.
This is allowed because it makes the method more usable. A caller of the Child
class’s doSomething
method only needs to handle IOException
, not SQLException
.
However, the reverse is not allowed. If the parent class’s method does not declare any exceptions, the overriding method in the child class cannot declare any checked exceptions.
class Parent {
public void doSomething() {
// ...
}
}
class Child extends Parent {
@Override
public void doSomething() throws IOException { // Compile-time error
// ...
}
}
This code will not compile because the overriding method (in Child
) declares a checked exception (IOException
) that the original method (in Parent
) does not declare.
The rule is that an overriding method can declare to throw fewer exceptions or narrower exceptions (subclasses of the declared exceptions) than the original method, but not more or broader exceptions.
This rule exists to ensure that a child class can always be used in place of its parent class without causing any unexpected checked exceptions. This is a fundamental principle of polymorphism and inheritance in Java.
However, notice that this only applies for checked exceptions. Unchecked exceptions can be added freely when overriding methods.
When an exception occurs in a Java program, it prints out a stack trace. A stack trace provides information about the exception and the state of the program when the exception occurred.
A stack trace can be incredibly useful when debugging a program. It tells you what went wrong and where in the code it went wrong.
Let’s look at an example stack trace:
Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.App.main(Bootstrap.java:14)
This stack trace is telling us that a NullPointerException
occurred in the getTitle
method of the Book
class, which was called from line 25 of the getBookTitles
method of the Author
class, which in turn was called from line 14 of the main
method of the App
class.
Each line in the stack trace represents a method call, with the most recent call at the top. The first line shows the thrown exception, followed by the method calls on the stack at that time.
For each method call, the stack trace shows:
To read a stack trace, you can start from the top and work your way down. The top line tells you what type of exception was thrown. The lines after that represent the method calls on the stack, with the most recent call at the top.
Each line provides a clue about the program’s state when the exception was thrown. You can use these clues to pinpoint the location in your code where the problem occurred.
When you encounter an exception in your Java program, one of the first steps in resolving the issue is to identify what type of exception it is. Previously, you learned about the hierarchy of exception classes, each designed to represent a specific type of problem. Recognizing these classes and understanding when they’re thrown can help you diagnose issues more quickly.
Tip 1: Read the Exception Class Name
The exception class name often indicates what went wrong. For example, a NullPointerException
suggests that you’re trying to use a null
reference, an ArrayIndexOutOfBoundsException
indicates that you’re trying to access an array with an invalid index, and an IOException
signals that something went wrong during an input/output operation.
Familiarizing yourself with the names and meanings of the most common exception classes can help you quickly identify issues in your code.
Tip 2: Understand the Exception Hierarchy
Understanding the Java exception hierarchy can also aid in recognizing exceptions. All exceptions in Java inherit from the Throwable
class, which has two main subclasses: Exception
and Error
.
Exceptions that inherit directly from the Exception
class are checked exceptions. These typically represent issues that should be handled in your code. Common examples include IOException
and SQLException
Exceptions that inherit from the RuntimeException
class (which is a subclass of Exception
) are unchecked exceptions. These often indicate programming errors, such as trying to access an array element with an out-of-bounds index (ArrayIndexOutOfBoundsException
) or trying to use a null
reference (NullPointerException
).
Errors, on the other hand, represent serious problems that a reasonable application should not try to catch. These are typically irrecoverable conditions, such as running out of memory (OutOfMemoryError
) or a stack overflow (StackOverflowError
).
Tip 3: Read the Exception Message When an exception is thrown, it usually includes a message with more details about what went wrong. This message can be incredibly helpful in diagnosing the issue.
For example, consider this exception message:
java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 5
This message indicates that the code is trying to access the element at index 10 in an array that only has 5 elements.
Tip 4: Look at the Stack Trace The stack trace that accompanies an exception can also provide valuable clues about what went wrong. The stack trace shows the sequence of method invocations that led to the exception.
Each line in the stack trace represents a method call, with the most recent call at the top. The line tells you the name of the method, the class it’s in, and the line number in the source code where the call occurred.
By tracing through the stack trace, you can often pinpoint the exact location in your code where the problem occurred.
Tip 5: Consult the Java API Documentation If you encounter an exception that you’re not familiar with, the Java API documentation can be a great resource. The documentation for each exception class provides information on when the exception is thrown and often includes examples of how to handle it.
For instance, the documentation for the ArrayIndexOutOfBoundsException
states:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
This provides a clear explanation of when you can expect to encounter this exception.
Finally, here’s a list of common unchecked and checked exceptions, as well as error classes:
Common Unchecked Exceptions Unchecked exceptions are those that are not checked at compile-time. They usually represent programming errors, such as logic mistakes or improper use of an API.
null
in a case where an object is required.Common Checked Exceptions Checked exceptions are those that are checked at compile-time. They usually represent conditions that a reasonable application might want to catch.
Common Error Classes Errors are usually thrown by the Java Virtual Machine and indicate serious problems that applications should not try to catch.
When an exception occurs in your Java program, you need to handle it to prevent your program from abruptly terminating. This is done using try-catch
blocks.
try-catch
BlockThe basic syntax of a try-catch block is as follows:
try {
// code that might throw an exception
} catch (ExceptionType e) {
// code to handle the exception
}
You place the code that might throw an exception in the try
block. If an exception occurs within the try
block, it is caught by the catch
block. The catch
block specifies the type of exception it can handle (ExceptionType
in the syntax above) and provides the code to handle that exception.
Here’s a concrete example:
try {
File file = new File("example.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
scanner.close();
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
In this example, we’re trying to read from a file named example.txt
. If the file doesn’t exist, a FileNotFoundException
will be thrown. The catch
block catches this exception and prints a message indicating that the file was not found.
You can use multiple catch
blocks to handle different types of exceptions. If an exception occurs in the try
block, Java will search for the first catch
block that can handle the exception, starting from the top.
try {
// code that might throw exceptions
} catch (IOException e) {
// handle IOException
} catch (SQLException e) {
// handle SQLException
}
In this example, if an IOException
occurs in the try
block, it will be handled by the first catch
block. If a SQLException
occurs, it will be handled by the second catch
block.
You can also catch multiple exceptions in a single catch
block. This is known as a multi-catch
block.
try {
// code that might throw exceptions
} catch (IOException | SQLException e) {
// handle either IOException or SQLException
}
In this example, the catch
block will handle either an IOException
or a SQLException
.
This can make your code more concise, but it should only be used when you want to handle the exceptions in the same manner. If you need to handle the exceptions differently, use separate catch
blocks.
Also, the multi-catch block must catch two or more unrelated exceptions. Unrelated exceptions do not share a parent-child relationship in the exception hierarchy, like IOException
and SQLException
in the previous example.
However, it’s important to order your catch
blocks from the most specific to the most general. This means placing catch blocks that catch subclasses of exceptions before those that catch their superclass exceptions. If you placed the IOException
catch block before the FileNotFoundException
catch block, the FileNotFoundException
catch block would never be reached because FileNotFoundException
is a subclass of IOException
. As a result, the IOException
catch block would catch all exceptions of type IOException
, including FileNotFoundException
, and the more specific handling code for FileNotFoundException
would be bypassed.
For example:
try {
// code that might throw exceptions
} catch (FileNotFoundException e) {
// handle FileNotFoundException
} catch (IOException e) {
// handle IOException
}
In this example, if a FileNotFoundException
occurs, it will be caught by the first catch
block. If a different IOException
occurs, it will be caught by the second catch
block. This ensures that specific exceptions are handled appropriately before more general exceptions.
finally
BlockThe finally
block is used to execute code that should always run, regardless of whether an exception was thrown or not:
try {
// code that might throw an exception
} catch (ExceptionType e) {
// handle the exception
} finally {
// code that always runs
}
The finally
block is often used for cleanup tasks, such as closing files or database connections.
If a return
statement is executed inside the try
block, the finally
block will still execute before the method returns:
public static int returnTest() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.println("Finally block");
}
}
In this example, even though we’re returning from inside the try
block, the finally
block will still execute and print "Finally block"
before the method returns.
The same is true if the return
statement is in a catch
block, the finally
block will still execute before the method returns.
However, finally
will not run if you call System.exit()
in the try
or catch
block. System.exit()
causes the Java Virtual Machine to exit, and the finally
block will not be executed before the program terminates:
try {
System.out.println("Try block");
System.exit(0);
} catch (Exception e) {
System.out.println("Catch block");
} finally {
System.out.println("Finally block");
}
In this example, we call System.exit(0)
in the try
block, so it will only print "Try block"
before the program terminates.
You can use a try
block with a finally
block and without any catch
blocks.
try {
// code that might throw an exception
} finally {
// code that always runs
}
This can be useful when you want to ensure that certain code always runs, even if an exception is thrown, but you don’t actually want to handle the exception in this method.
Lastly, it’s possible for the finally
block itself to throw an exception. If this happens, and there was also an exception in the try
block, the exception from the finally
block will be the one that’s actually thrown.
try {
throw new Exception("Exception in try");
} finally {
throw new Exception("Exception in finally");
}
In this example, the exception thrown in the finally
block will be the one that’s actually thrown by the method. The exception from the try
block will be suppressed.
try-with-resources
BlockIntroduced in Java 7, the try-with-resources
statement is a try
statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources
statement ensures that each resource is closed at the end of the statement.
The basic syntax of a try-with-resources
statement is:
try (Resource declaration) {
// use the resource
} catch (ExceptionType e1) {
// catch block
}
For a resource to be used in a try-with-resources
statement, it must implement the java.lang.AutoCloseable
interface. This interface has a single method, close()
, which is called automatically at the end of the try
block:
public interface AutoCloseable {
void close() throws Exception;
}
Alternatively, resources can implement the java.io.Closeable
interface:
public interface Closeable extends AutoCloseable {
void close() throws IOException;
}
They both declare a close()
method, and the only practical difference between these two interfaces is that the close
method of the Closeable
interface only throws exceptions of type IOException
, while the close
method of the AutoCloseable
interface throws exceptions of type Exception
(in other words, it can throw any kind of exception):
However, many of Java’s standard resources, such as Scanner
, FileReader
, and DatabaseConnection
, already implement AutoCloseable
.
Resources can be declared inside the parentheses of the try
statement, separated by semicolons if there are multiple resources.
try (Scanner scanner = new Scanner(new File("example.txt"));
PrintWriter writer = new PrintWriter(new File("output.txt"))) {
// use the resources
}
The resources are declared so they can be closed without doing it explicitly in a finally
block. Additionally, the resources declared in the try-with-resources
statement are only in scope inside the try
block. They are effectively final
, meaning you cannot assign a new value to them after they have been initialized.
So, if the resources are declared outside the try-with-resources
statement, they must be final:
final Scanner scanner = new Scanner(new File("example.txt"));
final PrintWriter writer = new PrintWriter(new File("output.txt"));
try (scanner; writer) {
// use the resources
}
Or effectively final:
Scanner scanner = new Scanner(new File("example.txt"));
PrintWriter writer = new PrintWriter(new File("output.txt"));
// No reassignment after initialization makes them effectively final
try (scanner; writer) {
// use the resources
}
If multiple resources are declared, they have to be separated by a semicolon and they are closed in the reverse order of their declaration. This is important if the resources depend on each other.
try (Scanner scanner = new Scanner(new File("example.txt"));
DatabaseConnection connection = DriverManager.getConnection(DB_URL)) {
// use the resources
}
In this example, connection will be closed before scanner.
As mentioned earlier, the resources declared in a try-with-resources
statement are effectively final
. While you don’t have to explicitly declare them as final
, you cannot assign a new value to them after they have been initialized:
try (Scanner scanner = new Scanner(new File("example.txt"))) {
scanner = new Scanner(new File("other.txt")); // This will not compile
}
However, one thing to be aware of with try-with-resources
is the possibility of suppressed exceptions.
Suppressed exceptions only occur when both the try
block and the close()
method throw exceptions.
If an exception is thrown from the try
block and another exception is thrown from the automatic close()
call, the exception from the close()
call is suppressed. It is added as a suppressed exception to the exception thrown from the try
block.
try (Scanner scanner = new Scanner(new File("example.txt"))) {
throw new IllegalStateException("Thrown from try");
}
If the call to scanner.close()
also throws an exception, that exception will be added as a suppressed exception to the IllegalStateException
.
You can retrieve these suppressed exceptions by calling the Throwable[] java.lang.Throwable.getSuppressed()
method on the exception thrown by the try
block:
try (Scanner scanner = new Scanner(new File("example.txt"))) {
throw new IllegalStateException("Thrown from try");
} catch (Exception e) {
System.err.println(e.getMessage());
Stream.of(e.getSuppressed())
.forEach(t -> System.err.println(t.getMessage()));
}
This is the output (assuming the close()
method throws an exception):
Thrown from try
Close Exception
An exception is an abnormal condition that disrupts the normal flow of a program. When an exception occurs, it is said to be thrown.
The purpose of exceptions is to handle errors gracefully and prevent the program from crashing or behaving unexpectedly.
All exception classes in Java are subtypes of the java.lang.Exception
class. The two main branches under Exception
are checked exceptions and unchecked exceptions (also known as runtime exceptions).
Checked exceptions are exceptional conditions that a well-written application should anticipate and handle, while unchecked exceptions are usually not recoverable.
An exception can be thrown automatically by the Java runtime or explicitly in code using the throw
statement.
Custom exceptions can be created by extending the Exception
class (for checked exceptions) or RuntimeException
class (for unchecked exceptions).
When a method throws an exception, it must declare this in its method signature using the throws
keyword. Only checked exceptions need to be declared.
A stack trace provides information about an exception and the state of the program when the exception occurred. It can be used to pinpoint the location in code where a problem occurred.
Exception classes can be recognized by their name, their place in the exception hierarchy, the exception message, and by consulting the Java API documentation.
Exceptions are handled using try-catch
blocks. The finally
block is used to execute code that should run regardless of whether an exception was thrown.
The multi-catch
block allows us to catch two or more unrelated exceptions with a single catch
block.
The finally
block is always executed, even when an exception is caught or when either the try
or catch
block contains a return
statement. However, the finally
block will not execute if the JVM exits during the try
or catch
block, such as by calling System.exit()
.
The try-with-resources
statement, introduced in Java 7, ensures that resources are properly closed after use. Resources used in a try-with-resources
statement must implement the AutoCloseable
or Closeable
interface.
1. Which of the following statements correctly describes a checked exception in Java?
A. A checked exception is a type of exception that inherits from the java.lang.RuntimeException
class.
B. A checked exception must be either caught or declared in the method signature using the throws
keyword.
C. A checked exception is an error that is typically caused by the environment in which the application is running, and it cannot be handled by the application.
D. A checked exception can be thrown by the Java Virtual Machine when a severe error occurs, such as an out-of-memory error.
2. Which of the following code snippets correctly defines and throws a custom checked exception?
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class TestCustomException {
public static void main(String[] args) {
try {
methodThatThrowsException();
} catch (CustomException e) {
System.out.println(e.getMessage());
}
}
public static void methodThatThrowsException() throws CustomException {
throw new CustomException("This is a custom checked exception");
}
}
A. This code defines a custom checked exception and correctly throws and handles it.
B. This code defines a custom unchecked exception.
C. This code will not compile because the custom exception is not declared correctly in the method signature.
D. This code will compile but will not throw the custom exception at runtime.
3. Given the following class, what is the result?
public class Main {
protected static int myMethod() {
try {
throw new RuntimeException();
} catch(RuntimeException e) {
return 1;
} finally {
return 2;
}
}
public static void main(String[] args) {
System.out.println(myMethod());
}
}
A. 1
B. 2
C. Compilation fails
D. An exception occurs at runtime
4. Given the following class, which of the following statement is true?
public class Main {
public static void main(String[] args) {
try {
// Do nothing
} finally {
// Do nothing
}
}
}
A. The code doesn’t compile correctly.
B. The code would compile correctly if we add a catch
block.
C. The code would compile correctly if we remove the finally
block.
D. The code compiles correctly as it is.
5. Which of the following statements are true? (Choose all that apply)
A. In a try-with-resources
, the catch
block is required.
B. The throw
keyword is used to throw an exception.
C. In a try-with-resources
block, if you declare more than one resource, they have to be separated by a semicolon.
D. If a catch
block is defined for an exception that couldn’t be thrown by the code in the try
block, a compile-time error is generated.
6. Given the following class, what is the result?:
class Connection implements java.io.Closeable {
public void close() throws IOException {
throw new IOException("Close Exception");
}
}
public class Main {
public static void main(String[] args) {
try (Connection c = new Connection()) {
throw new RuntimeException("RuntimeException");
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
A. Close Exception
B. RuntimeException
C. RuntimeException
and then CloseException
D. Compilation fails
E. The stack trace of an uncaught exception is printed
7. Which of the following exceptions are direct subclasses of RuntimeException
?
A. java.io.FileNotFoundException
B. java.lang.ArithmeticException
C. java.lang.ClassCastException
D. java.lang.InterruptedException
8. Given the following code, what is the result?
class MyResource implements AutoCloseable {
public void close() {
throw new RuntimeException("Close Exception");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource resource = new MyResource()) {
throw new RuntimeException("Try Block Exception");
} catch (RuntimeException e) {
Throwable[] suppressed = e.getSuppressed();
if (suppressed.length > 0) {
for (Throwable t : suppressed) {
System.out.println("Suppressed: " + t.getMessage());
}
} else {
System.out.println(e.getMessage());
}
}
}
}
A. Only "Try Block Exception"
is printed.
B. Only "Close Exception"
is printed.
C. Both "Try Block Exception"
and "Close Exception"
are printed.
D. "Suppressed: Close Exception"
is printed.
Do you like what you read? Would you consider?
Do you have a problem or something to say?