Java Exceptions Interview Questions (+ Answers) – Java异常面试问题(+答案)

最后修改: 2017年 4月 18日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Exceptions are an essential topic that every Java developer should be familiar with. This article provides answers to some of the questions that might pop up during an interview.

异常是每个Java开发者都应该熟悉的一个基本话题。本文对面试中可能出现的一些问题进行了解答。

2. Questions

2.问题

Q1. What Is an Exception?

Q1.什么是例外?

An exception is an abnormal event that occurs during the execution of a program and disrupts the normal flow of the program’s instructions.

异常是指在程序执行过程中发生的异常事件,它扰乱了程序的正常指令流。

Q2. What Is the Purpose of the Throw and Throws Keywords?

Q2.抛出和抛出关键词的目的是什么?

The throws keyword is used to specify that a method may raise an exception during its execution. It enforces explicit exception handling when calling a method:

throws关键字用于指定一个方法在其执行过程中可能会引发一个异常。在调用一个方法时,它强制执行明确的异常处理。

public void simpleMethod() throws Exception {
    // ...
}

The throw keyword allows us to throw an exception object to interrupt the normal flow of the program. This is most commonly used when a program fails to satisfy a given condition:

throw关键字允许我们抛出一个异常对象来中断程序的正常流程。这在程序不能满足某个特定条件时最常用。

if (task.isTooComplicated()) {
    throw new TooComplicatedException("The task is too complicated");
}

Q3. How Can You Handle an Exception?

Q3.如何处理异常?

By using a try-catch-finally statement:

通过使用try-catch-finally语句。

try {
    // ...
} catch (ExceptionType1 ex) {
    // ...
} catch (ExceptionType2 ex) {
    // ...
} finally {
    // ...
}

The block of code in which an exception may occur is enclosed in a try block. This block is also called “protected” or “guarded” code.

可能发生异常的代码块被封在一个try块中。这个代码块也被称为 “受保护 “或 “受保护 “的代码。

If an exception occurs, the catch block that matches the exception being thrown is executed, if not, all catch blocks are ignored.

如果发生异常,与被抛出的异常相匹配的catch块被执行,如果没有,所有的catch块被忽略。

The finally block is always executed after the try block exits, whether an exception was thrown or not inside it.

finally块总是在try块退出后执行,无论里面是否抛出了异常。

Q4. How Can You Catch Multiple Exceptions?

Q4.如何捕获多个异常?

There are three ways of handling multiple exceptions in a block of code.

有三种方法来处理一个代码块中的多个异常。

The first is to use a catch block that can handle all exception types being thrown:

首先是使用一个catch块,可以处理所有被抛出的异常类型。

try {
    // ...
} catch (Exception ex) {
    // ...
}

You should keep in mind that the recommended practice is to use exception handlers that are as accurate as possible.

你应该记住,推荐的做法是使用尽可能准确的异常处理程序。

Exception handlers that are too broad can make your code more error-prone, catch exceptions that weren’t anticipated, and cause unexpected behavior in your program.

过于宽泛的异常处理程序会使你的代码更容易出错,捕捉到没有预料到的异常,并导致你的程序出现意外行为。

The second way is implementing multiple catch blocks:

第二种方式是实现多个抓取块。

try {
    // ...
} catch (FileNotFoundException ex) {
    // ...
} catch (EOFException ex) {
    // ...
}

Note that, if the exceptions have an inheritance relationship; the child type must come first and the parent type later. If we fail to do this, it will result in a compilation error.

注意,如果异常有继承关系;子类型必须在前,父类型在后。如果我们没有做到这一点,将导致编译错误。

The third is to use a multi-catch block:

第三种是使用多抓取块。

try {
    // ...
} catch (FileNotFoundException | EOFException ex) {
    // ...
}

This feature, first introduced in Java 7; reduces code duplication and makes it easier to maintain.

这一功能在Java 7中首次引入;减少了代码的重复,使其更容易维护。

Q5. What Is the Difference Between a Checked and an Unchecked Exception?

Q5.检查过的异常和未检查过的异常之间有什么区别?

A checked exception must be handled within a try-catch block or declared in a throws clause; whereas an unchecked exception is not required to be handled nor declared.

被检查的异常必须在try-catch块中处理,或者在throws子句中声明;而未被检查的异常则不需要处理或声明。

Checked and unchecked exceptions are also known as compile-time and runtime exceptions respectively.

被检查和未被检查的异常也分别被称为编译时和运行时异常。

All exceptions are checked exceptions, except those indicated by Error, RuntimeException, and their subclasses.

除了那些由ErrorRuntimeException和它们的子类所表示的异常,所有的异常都是经过检查的异常。

Q6. What Is the Difference Between an Exception and Error?

Q6.异常和错误之间的区别是什么?

An exception is an event that represents a condition from which is possible to recover, whereas error represents an external situation usually impossible to recover from.

异常是一个代表有可能恢复的条件的事件,而错误代表通常不可能恢复的外部情况。

All errors thrown by the JVM are instances of Error or one of its subclasses, the more common ones include but are not limited to:

JVM抛出的所有错误都是Error或其子类之一的实例,更常见的错误包括但不限于:。

  • OutOfMemoryError – thrown when the JVM cannot allocate more objects because it is out memory, and the garbage collector was unable to make more available
  • StackOverflowError – occurs when the stack space for a thread has run out, typically because an application recurses too deeply
  • ExceptionInInitializerError – signals that an unexpected exception occurred during the evaluation of a static initializer
  • NoClassDefFoundError – is thrown when the classloader tries to load the definition of a class and couldn’t find it, usually because the required class files were not found in the classpath
  • UnsupportedClassVersionError – occurs when the JVM attempts to read a class file and determines that the version in the file is not supported, normally because the file was generated with a newer version of Java

Although an error can be handled with a try statement, this is not a recommended practice since there is no guarantee that the program will be able to do anything reliably after the error was thrown.

尽管可以用try语句来处理一个错误,但这并不是一个值得推荐的做法,因为不能保证程序在抛出错误后还能可靠地做任何事情。

Q7. What Exception Will Be Thrown Executing the Following Code Block?

Q7.在执行以下代码块时将会抛出什么异常?

Integer[][] ints = { { 1, 2, 3 }, { null }, { 7, 8, 9 } };
System.out.println("value = " + ints[1][1].intValue());

It throws an ArrayIndexOutOfBoundsException since we’re trying to access a position greater than the length of the array.

它抛出了一个ArrayIndexOutOfBoundsException,因为我们正试图访问一个大于数组长度的位置。

Q8. What Is Exception Chaining?

Q8.什么是异常链?

Occurs when an exception is thrown in response to another exception. This allows us to discover the complete history of our raised problem:

当一个异常被抛出以响应另一个异常时发生。这使我们能够发现我们提出的问题的完整历史。

try {
    task.readConfigFile();
} catch (FileNotFoundException ex) {
    throw new TaskException("Could not perform task", ex);
}

Q9. What Is a Stacktrace and How Does It Relate to an Exception?

Q9.什么是堆栈跟踪,它与异常有什么关系?

A stack trace provides the names of the classes and methods that were called, from the start of the application to the point an exception occurred.

堆栈跟踪提供了从应用程序开始到异常发生时被调用的类和方法的名称。

It’s a very useful debugging tool since it enables us to determine exactly where the exception was thrown in the application and the original causes that led to it.

这是一个非常有用的调试工具,因为它使我们能够准确地确定在应用程序中抛出异常的位置以及导致异常的原始原因。

Q10. Why Would You Want to Subclass an Exception?

Q10.你为什么要对一个异常进行子类化?

If the exception type isn’t represented by those that already exist in the Java platform, or if you need to provide more information to client code to treat it in a more precise manner, then you should create a custom exception.

如果这个异常类型没有被那些已经存在于Java平台中的异常所代表,或者你需要向客户代码提供更多的信息,以更精确的方式处理它,那么你应该创建一个自定义的异常。

Deciding whether a custom exception should be checked or unchecked depends entirely on the business case. However, as a rule of thumb; if the code using your exception can be expected to recover from it, then create a checked exception otherwise make it unchecked.

决定一个自定义的异常应该被检查还是不被检查,完全取决于业务情况。然而,作为一个经验法则,如果使用你的异常的代码可以从它那里恢复,那么就创建一个有检查的异常,否则就使它成为无检查的。

Also, you should inherit from the most specific Exception subclass that closely relates to the one you want to throw. If there is no such class, then choose Exception as the parent.

另外,你应该继承与你想抛出的异常密切相关的最具体的Exception子类。如果没有这样的类,那么就选择Exception作为父类。

Q11. What Are Some Advantages of Exceptions?

Q11.例外的一些优势是什么?

Traditional error detection and handling techniques often lead to spaghetti code hard to maintain and difficult to read. However, exceptions enable us to separate the core logic of our application from the details of what to do when something unexpected happens.

传统的错误检测和处理技术往往会导致难以维护和难以阅读的面条状代码。然而,异常使我们能够将应用程序的核心逻辑与当意外情况发生时如何处理的细节分开。

Also, since the JVM searches backward through the call stack to find any methods interested in handling a particular exception; we gain the ability to propagate an error up in the call stack without writing additional code.

此外,由于JVM通过调用堆栈向后搜索,以找到任何对处理特定异常感兴趣的方法;我们获得了在调用堆栈中向上传播错误的能力,而无需编写额外的代码。

Also, because all exceptions thrown in a program are objects, they can be grouped or categorized based on its class hierarchy. This allows us to catch a group of exceptions in a single exception handler by specifying the exception’s superclass in the catch block.

另外,由于在程序中抛出的所有异常都是对象,它们可以根据其类的层次结构进行分组或分类。这使得我们可以通过在catch块中指定异常的超类,在单个异常处理程序中捕获一组异常。

Q12. Can You Throw Any Exception Inside a Lambda Expression’s Body?

Q12.你能在Lambda表达式内部抛出任何异常吗?

When using a standard functional interface already provided by Java, you can only throw unchecked exceptions because standard functional interfaces do not have a “throws” clause in method signatures:

当使用Java已经提供的标准函数式接口时,你只能抛出未检查的异常,因为标准函数式接口在方法签名中没有 “throws “条款。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.forEach(i -> {
    if (i == 0) {
        throw new IllegalArgumentException("Zero not allowed");
    }
    System.out.println(Math.PI / i);
});

However, if you are using a custom functional interface, throwing checked exceptions is possible:

然而,如果你使用的是一个自定义的功能接口,抛出检查过的异常是可能的。

@FunctionalInterface
public static interface CheckedFunction<T> {
    void apply(T t) throws Exception;
}
public void processTasks(
  List<Task> taks, CheckedFunction<Task> checkedFunction) {
    for (Task task : taks) {
        try {
            checkedFunction.apply(task);
        } catch (Exception e) {
            // ...
        }
    }
}

processTasks(taskList, t -> {
    // ...
    throw new Exception("Something happened");
});

Q13. What Are the Rules We Need to Follow When Overriding a Method That Throws an Exception?

Q13.当重写一个抛出异常的方法时,我们需要遵循哪些规则?

Several rules dictate how exceptions must be declared in the context of inheritance.

有几条规则规定了在继承的背景下必须如何声明异常。

When the parent class method doesn’t throw any exceptions, the child class method can’t throw any checked exception, but it may throw any unchecked.

当父类方法不抛出任何异常时,子类方法不能抛出任何有检查的异常,但它可以抛出任何无检查的异常。

Here’s an example code to demonstrate this:

这里有一个例子代码来证明这一点。

class Parent {
    void doSomething() {
        // ...
    }
}

class Child extends Parent {
    void doSomething() throws IllegalArgumentException {
        // ...
    }
}

The next example will fail to compile since the overriding method throws a checked exception not declared in the overridden method:

下一个例子将无法编译,因为重写方法抛出了一个没有在重写方法中声明的检查异常。

class Parent {
    void doSomething() {
        // ...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
        // Compilation error
    }
}

When the parent class method throws one or more checked exceptions, the child class method can throw any unchecked exception; all, none or a subset of the declared checked exceptions, and even a greater number of these as long as they have the same scope or narrower.

当父类方法抛出一个或多个检查过的异常时,子类方法可以抛出任何未检查过的异常;所有的、没有的或已声明的检查过的异常的子集,甚至更多的这些异常,只要它们的范围相同或更窄。

Here’s an example code that successfully follows the previous rule:

下面是一个成功遵循前述规则的示例代码。

class Parent {
    void doSomething() throws IOException, ParseException {
        // ...
    }

    void doSomethingElse() throws IOException {
        // ...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
        // ...
    }

    void doSomethingElse() throws FileNotFoundException, EOFException {
        // ...
    }
}

Note that both methods respect the rule. The first throws fewer exceptions than the overridden method, and the second, even though it throws more; they’re narrower in scope.

请注意,这两个方法都尊重规则。第一个方法抛出的异常比被覆盖的方法少,而第二个方法,尽管它抛出了更多的异常;它们的范围更窄。

However, if we try to throw a checked exception that the parent class method doesn’t declare or we throw one with a broader scope; we’ll get a compilation error:

然而,如果我们试图抛出一个父类方法没有声明的检查异常,或者我们抛出一个范围更广的异常;我们会得到一个编译错误。

class Parent {
    void doSomething() throws FileNotFoundException {
        // ...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
        // Compilation error
    }
}

When the parent class method has a throws clause with an unchecked exception, the child class method can throw none or any number of unchecked exceptions, even though they are not related.

当父类方法有一个带有未检查异常的throws子句时,子类方法可以不抛出任何或任何数量的未检查异常,即使它们之间没有关系。

Here’s an example that honors the rule:

下面是一个遵守该规则的例子。

class Parent {
    void doSomething() throws IllegalArgumentException {
        // ...
    }
}

class Child extends Parent {
    void doSomething()
      throws ArithmeticException, BufferOverflowException {
        // ...
    }
}

Q14. Will the Following Code Compile?

Q14.以下代码是否可以编译?

void doSomething() {
    // ...
    throw new RuntimeException(new Exception("Chained Exception"));
}

Yes. When chaining exceptions, the compiler only cares about the first one in the chain and, because it detects an unchecked exception, we don’t need to add a throws clause.

是的。当连锁异常时,编译器只关心连锁中的第一个,而且因为它检测到了一个未检查的异常,我们不需要添加throws子句。

Q15. Is There Any Way of Throwing a Checked Exception from a Method That Does Not Have a Throws Clause?

Q15.是否有办法从一个没有Throws条款的方法中抛出一个被检查的异常?

Yes. We can take advantage of the type erasure performed by the compiler and make it think we are throwing an unchecked exception, when, in fact; we’re throwing a checked exception:

是的。我们可以利用编译器进行的类型清除,让它认为我们抛出的是一个未检查的异常,而事实上,我们抛出的是一个检查的异常。

public <T extends Throwable> T sneakyThrow(Throwable ex) throws T {
    throw (T) ex;
}

public void methodWithoutThrows() {
    this.<RuntimeException>sneakyThrow(new Exception("Checked Exception"));
}

3. Conclusion

3.结论

In this article, we’ve explored some of the questions that are likely to appear in technical interviews for Java developers, regarding exceptions. This is not an exhaustive list, and it should be treated only as the start of further research.

在这篇文章中,我们探讨了一些可能出现在Java开发人员技术面试中的关于异常的问题。这并不是一个详尽的列表,它只应该被当作进一步研究的开始。

We, at Baeldung, wish you success in any upcoming interviews.

我们,在Baeldung,祝你在即将到来的面试中取得成功。

Next »

Java Annotations Interview Questions (+ Answers)

« Previous

Java Flow Control Interview Questions (+ Answers)