【Java】关于异常你需要知道的事情

异常体系

异常体系

异常声明

  • 如果声明的是Exception,那么必须要处理
  • 如果声明的是RuntimeException,那么可以不被处理

捕获多个异常

在Java中,如果你希望捕获try代码块中可能抛出的多种异常,有几种不同的方法可以实现:

  1. 多个catch块:为每种异常类型提供一个单独的catch块。每个catch块处理一种特定的异常类型。
try {
    // 可能会抛出多种异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2
}
// ... 可以根据需要添加更多的 catch 块
  1. 通用的catch块:使用一个通用的catch块来捕获所有未被捕获的异常。这通常不是一个好习惯,因为它隐藏了具体的错误类型,使得调试更加困难。
try {
    // 可能会抛出多种异常的代码
} catch (Exception e) {
    // 捕获所有Exception的子类,不推荐这样做,因为不清楚具体是哪种异常
}
  1. 多异常类型捕获:从Java 7开始,你可以在一个catch块中捕获多个异常类型,使用圆括号将异常类型包围起来。
try {
    // 可能会抛出多种异常的代码
} catch (ExceptionType1 | ExceptionType2 | ExceptionType3 e) {
    // 同时处理 ExceptionType1, ExceptionType2 和 ExceptionType3
}
  1. ** finally 块**:如果无论是否发生异常,都需要执行一些代码(如资源清理),可以使用finally块。finally块总是在trycatch块之后执行。
try {
    // 可能会抛出异常的代码
} catch (ExceptionType1 | ExceptionType2 | ExceptionType3 e) {
    // 处理异常
} finally {
    // 无论是否发生异常都会执行的代码
}
  1. 异常链:当捕获一个异常并且需要抛出一个新的异常时,可以使用Throwable类的addSuppressed()方法或构造函数中的cause参数来保留原始异常的信息,形成异常链。
try {
    // 可能会抛出多种异常的代码
} catch (ExceptionType1 | ExceptionType2 e) {
    throw new WrappedException("Error message", e);
}

在这个例子中,WrappedException是一个新的异常类型,它封装了捕获的异常作为其原因(cause)。

选择使用哪种方法取决于你的具体需求:

  • 如果不同的异常需要不同的处理逻辑,使用多个catch块。
  • 如果你想要记录或以不同方式响应不同类型的异常,可以考虑使用多异常类型捕获。
  • 如果你想要执行一些清理工作,无论是否发生异常,都使用finally块。
  • 如果你想要封装异常并抛出一个新的异常,同时保留原始异常信息,使用异常链。

通常,推荐的做法是尽可能具体地捕获和处理异常,避免使用过于宽泛的异常捕获,这样可以使你的代码更加健壮,并且便于调试。

Java中的哪些异常,程序不用捕获处理?【重要】

在Java中,异常分为两种主要类型:受检异常(Checked Exceptions)和非受检异常(Unchecked Exceptions)。

  1. 受检异常(Checked Exceptions):这些是继承自java.lang.Exception类但不是继承自java.lang.RuntimeException的异常。受检异常必须在方法中被捕获或者声明抛出。编译器会强制要求你处理这些异常,因为它们被认为是可以被预见并处理的情况。例如,IOExceptionSQLException就是受检异常。

  2. 非受检异常(Unchecked Exceptions):这些是继承自java.lang.RuntimeException的异常。非受检异常不需要在方法中被捕获或声明抛出。它们通常表示编程错误,如空指针异常(NullPointerException)、数组越界异常(ArrayIndexOutOfBoundsException)和非法参数异常(IllegalArgumentException)等。

对于非受检异常,程序可以选择不捕获处理,但这通常不推荐,因为不处理这些异常可能导致程序崩溃。然而,有些情况下,你可能决定不捕获特定的非受检异常,原因可能包括:

  • 不可恢复的错误:当异常指示了一种无法恢复或者无需恢复的错误时,例如,程序的配置错误或严重违反了预期的运行时假设,你可能选择不捕获它,让程序崩溃并记录错误日志。

  • 性能考虑:捕获异常是有性能成本的,对于性能敏感的代码段,如果异常发生的概率非常低,你可能选择不捕获。

  • 框架或库的要求:某些框架或库可能要求你不捕获异常,以便它们可以在更高级别处理异常。

  • 简化代码:在某些情况下,异常处理可能会使代码变得复杂,如果异常发生的可能性非常低,且对程序的影响不大,开发者可能会选择不捕获。

尽管如此,通常建议至少对所有可能的受检异常提供处理逻辑,以避免程序因未处理的异常而意外终止。对于非受检异常,即使选择不捕获它们,也应该在设计和文档中明确这一点,并确保它们不会对程序的其他部分产生不良影响。此外,对于关键的应用部分,记录日志是一个好习惯,这样即使程序崩溃,也能够了解崩溃的原因。

try with resource 异常处理流程

  • 这里其实就是要注意,哪几种情况会异常会被catch住
    在这里插入图片描述

foreach中遇到异常

  • foreach循环会自动跳过遍历空集合,如果对于有null值的集合,碰到null时需注意NPE

在Java中,使用foreach(也称为增强型for循环)进行迭代时,不推荐进行元素的removeadd操作,原因如下:

  1. 迭代器失效:在foreach循环中,实际上是使用迭代器来遍历集合的。当你尝试在迭代过程中修改集合(添加或删除元素),会导致迭代器失效,即迭代器不再能够安全地指向集合中的下一个元素。

  2. 并发修改异常:尝试在迭代过程中修改集合可能会抛出ConcurrentModificationException。这是因为foreach循环隐式地为集合创建了一个迭代器,并在每次迭代时使用迭代器的next()hasNext()方法。如果在迭代过程中修改了集合,就会违反迭代器的预期状态,导致异常。

  3. 逻辑错误:即使在某些情况下,如使用ArrayList,你可能会侥幸逃脱没有遇到异常,但这样的操作通常会导致逻辑错误。因为你可能会跳过一些元素或者重复处理一些元素,导致程序行为与预期不符。

  4. 性能问题:即使某些集合类型(如LinkedList)支持在迭代过程中进行添加或删除操作,这样做也可能引起性能问题。因为每个removeadd操作都可能涉及到大量的元素移动和列表的重新链接,这在大型集合上尤其低效。

如果你需要在迭代过程中修改集合,应该使用集合的迭代器来安全地进行这些操作。例如,对于ArrayList,可以先复制需要删除的元素到另一个集合,然后在迭代结束后删除它们:

List<String> list = ...; // 假设这是你的列表
List<String> toRemove = new ArrayList<>();

for (String item : list) {
    if (需要删除的条件) {
        toRemove.add(item);
    }
}

list.removeAll(toRemove);

对于LinkedList,可以直接使用其迭代器进行删除和添加操作:

List<String> list = new LinkedList<>(); // 使用LinkedList
Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {
    String item = iterator.next();
    if (需要删除的条件) {
        iterator.remove();
    }
    // 可以在这里添加新元素到list中,不会导致迭代器失效
}

总之,避免在foreach循环中修改集合是为了确保逻辑的正确性、避免异常和潜在的性能问题。如果需要修改,应该使用集合的迭代器或者其它安全的方法来进行。

面试题

try和finally中都由return

在这里插入图片描述

  • 31
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值