Java异常处理与日志记录全解析
立即解锁
发布时间: 2025-08-18 02:24:31 阅读量: 3 订阅数: 13 

### Java异常处理与日志记录全解析
#### 1. 锁的释放与异常处理
在函数中,为了确保锁在函数结束时无论是否抛出异常(检查异常或非检查异常)都能被释放,应该在函数开始时获取锁,并在`finally`块中释放它。例如,若`mylock.unlock()`函数调用不在`finally`块中(而是在`try`块末尾),当发生异常时,`mylock.unlock()`调用将不会执行,因为代码执行会在异常发生处中断,导致锁永远被占用而无法释放。
**注意**:如果需要在方法中返回值,在`finally`块中返回值时要格外小心。`finally`块中的`return`语句总是会执行,无论`try`块中是否有其他`return`语句。
#### 2. 抛出异常
- **问题**:需要在代码中通过抛出异常来处理特殊问题,并且希望终止当前代码路径的执行。
- **解决方案**:使用`throw`关键字可以向当前线程发出信号,让其查找能够处理所抛出异常的`try/catch`块(从当前级别开始向上查找栈)。例如:
```java
private void start() {
try {
callSomeMethodThatMightThrow(null);
} catch (IllegalArgumentException e) {
System.out.println("There was an illegal argument exception!");
}
}
private void callSomeFunctionThatMightThrow(Object o) {
if (o == null) throw new NullPointerException("The object is null");
}
```
在这个代码示例中,`callSomeMethodThatMightThrow`会检查参数的有效性。如果参数无效,它会抛出`IllegalArgumentException`,表明该方法的调用者使用了错误的参数。
- **工作原理**:`throw`关键字允许你显式地生成异常条件。当当前线程抛出异常时,它不会执行`throw`语句之后的任何代码,而是将控制权转移到`catch`子句(如果有)或终止线程。
**注意**:抛出异常时,要确保确实需要抛出它。如果异常在向上传播过程中未被捕获,它将终止正在执行的线程(也称为展开)。如果程序只有一个主线程,未捕获的异常将终止程序。
#### 3. 捕获多个异常
- **问题**:希望捕获`try`块中可能发生的多个异常。
- **解决方案1**:使用不同的`catch`子句(从最具体到最通用的顺序排列)可以捕获多个异常。示例代码如下:
```java
try {
Class<?> stringClass = Class.forName("java.lang.String");
FileInputStream in = new FileInputStream("myFile.log"); // Can throw IOException
in.read();
} catch (IOException e) {
System.out.println("There was an IOException " + e);
} catch (ClassNotFoundException e) {
System.out.println("There was a ClassCastException " + e);
}
```
- **解决方案2**:如果不同异常的处理代码相同,在Java 7中可以使用`|`运算符来捕获多个异常(Java 7中的多捕获异常)。示例代码如下:
```java
try {
Class<?> stringClass = Class.forName("java.lang.String");
FileInputStream in = new FileInputStream("myFile.log"); // Can throw IOException
in.read();
} catch (IOException | ClassNotFoundException e) {
System.out.println("An exception of type " + e.getClass() + " was thrown! " + e);
}
```
- **工作原理**:通过使用不同的`catch`子句,可以调整特定异常抛出时执行的代码。有时,我们只是捕获给定代码中可能抛出的所有检查异常,并希望以相同的方式处理它们(例如记录日志)。在这种情况下,可以使用Java 7的新结构,在一个`catch`块中指定所有要捕获的异常。
**注意**:如果在多个`catch`块中捕获异常(解决方案1),请确保`catch`块从最具体到最通用的顺序定义。不遵循此约定将导致异常无法被更具体的块处理。当存在`catch (Exception e)`块时,这一点尤为重要,因为它几乎可以捕获所有异常。使用`catch (Exception e)`块(称为全捕获或宝可梦异常处理程序)通常不是一个好的做法,因为这样的块会捕获所有类型的异常并以相同的方式处理它们,可能会捕获到调用栈深处的异常,而这可能不是你想要的。
#### 4. 捕获未捕获的异常
- **问题**:希望知道线程何时因未捕获的异常(如`NullPointerException`)而终止。
- **解决方案1**:在创建Java线程时,有时不仅要捕获检查异常,还要捕获任何类型的异常,至少要正确记录它们,或者继续执行以避免执行线程的终止。为此,Java允许为每个线程或全局注册一个`ExceptionHandler()`。例如,以下代码为每个线程注册一个处理程序:
```java
private void start() {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Woa! there was an exception thrown somewhere! " + t.getName() + ": " + e);
}
});
final Random random = new Random();
for (int j = 0; j < 10; j++) {
int divisor = random.nextInt(4);
System.out.println("200 / " + divisor + " Is " + (200 / divisor));
}
}
```
- **解决方案2**:使用线程自己的`UncaughtExceptionHandler()`。线程中发生的任何未捕获异常都将由`UncaughtExceptionHandler()`的`uncaughtException()`方法处理。例如:
```java
Thread.currentThread().setUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("In this thread " + t.getName() + " an exception was thrown " + e);
}
});
Thread someThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(200 / 0);
}
});
someThread.setName("Some Unlucky Thread");
someThread.start();
System.out.println("In the main thread " + (200 / 0));
```
- **工作原理**:`Thread.defaultUncaughtExceptionHandler()`将为每个未捕获的非检查异常调用。当`UncaughtExceptionHandler()`处理异常时,意味着没有`try/catch`块能够捕获该异常,因此它会一直向上冒泡到线程栈。这是线程终止前执行的最后一段代码。当异常在线程的或默认的`U
0
0
复制全文
相关推荐










