Guava处理异常

guava由Google开发,它提供了大量的核心Java库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理和I/O操作等。

异常处理

传统的Java异常处理通常包括try-catch-finally块和throws关键字。

遇到FileNotFoundException或IOException

java 复制代码
try {
    // 读取文件的操作
} catch (FileNotFoundException e) {
    // 处理文件未找到的情况
} catch (IOException e) {
    // 处理读取文件时的IO异常
} finally {
    // 最后,不管有没有异常,都要执行的代码,比如关闭文件流
}

有时候一个方法里面可能需要捕获多种异常,这就导致了代码的复杂度急剧上升。很多时候咱们还需要把捕获到的异常转换成另一种异常再抛出,这就需要咱们手动处理异常的传播,代码就更加复杂了

而Guava的Throwables类,就是为了解决这些问题而生的。它提供了一系列静态方法,帮助咱们简化异常的处理和传播。比如,咱们可以用Throwables.propagate来把检查异常转换为运行时异常,或者用Throwables.getStackTraceAsString获取异常的堆栈字符串,这些都是在传统Java异常处理中比较难实现的。

java 复制代码
public void doSomethingRisky() {
    try {
        // 一些可能抛出检查型异常的代码
    } catch (IOException e) {
        // 使用Throwables.propagate将检查型异常转换为未检查型异常
        throw Throwables.propagate(e);
    }
}

这样做的好处:不需要在方法签名中声明所有可能的异常,简化了代码。但同时,它也保留了原始异常信息,便于调试和错误追踪。

另一个超级有用的功能是Throwables.getStackTraceAsString(Throwable)。有时候,咱们需要将异常的堆栈信息记录到日志中,或者发送到某个监控系统。这个方法可以直接把异常的堆栈信息转换为字符串,方便咱们处理:

java 复制代码
try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 获取异常的堆栈信息字符串
    String stackTrace = Throwables.getStackTraceAsString(e);
    // 做些什么,比如记录日志
}

此外,Throwables.getRootCause(Throwable) 也很实用。有时候异常会被包装多层,最原始的异常信息可能隐藏在几层包装之下。这个方法可以帮咱们直接找到最底层的异常原因,方便定位问题:

java 复制代码
try {
    // 一些可能抛出包装过的异常的操作
} catch (Exception e) {
    // 直接找到根本原因
    Throwable rootCause = Throwables.getRootCause(e);
    // 处理或记录根本原因
}

通过这些方法,Throwables类帮咱们简化了异常的处理过程,让异常信息更加清晰,调试更加方便。

实际应用:

案例一:

读取文件内容的方法,在传统的Java处理方式中,你可能会遇到FileNotFoundException和IOException

java 复制代码
public String readFile(String path) throws IOException {
    try {
        // 读取文件的操作
        return ...;
    } catch (FileNotFoundException e) {
        // 处理文件未找到的情况
    } catch (IOException e) {
        // 处理读取文件时的IO异常
    } finally {
        // 关闭资源
    }
}

但是,使用Guava的Throwables

java 复制代码
public String readFile(String path) {
    try {
        // 读取文件的操作
        return ...;
    } catch (Exception e) {
        Throwables.throwIfInstanceOf(e, IOException.class);
        throw Throwables.propagate(e);
    } finally {
        // 关闭资源
    }
}

在这个例子中,throwIfInstanceOf方法会检查捕获的异常是否是指定类型的实例。如果是,就抛出异常;如果不是,就用propagate方法将它转换为运行时异常。这样做的好处是减少了代码量,同时保留了异常处理的清晰性和准确性。

案例二:

处理数据库操作时遇到了异常,这个异常可能被多层包装。传统的做法可能需要逐层检查

用Guava可以简化这一过程

java 复制代码
try {
    // 一些数据库操作,可能会抛出SQLException
} catch (Exception e) {
    Throwable rootCause = Throwables.getRootCause(e);//getRootCause方法快速定位到最底层的异常原因,这对于调试和异常处理来说非常有用
    if (rootCause instanceof SQLException) {
        // 处理SQL异常
    }
}

案例三:

把异常信息记录到日志中。

java 复制代码
try {
    // 可能会出现异常的操作
} catch (Exception e) {
    logger.error("An error occurred: " + e.getMessage(), e);
}

但是,有时候仅仅记录异常信息还不够,咱们还需要异常的完整堆栈跟踪。

java 复制代码
//能在日志中获得完整的异常堆栈信息,对于后期的问题分析和修复大有帮助。
try {
    // 可能会出现异常的操作
} catch (Exception e) {
    logger.error("An error occurred: " + Throwables.getStackTraceAsString(e));
}

最佳异常日志记录,当捕获到异常时,除了记录异常消息,咱们还可以记录整个异常堆栈:

即使异常被捕获并处理,咱们也能在日志中得到足够的信息来分析问题。

java 复制代码
try {
    // 可能抛出异常的操作
} catch (Exception e) {
    logger.error("Exception occurred: " + e.toString());
    logger.error("Stack trace: " + Throwables.getStackTraceAsString(e));
}

案例四:

链式异常处理

java 复制代码
/**
	throwIfInstanceOf方法按顺序检查异常类型。
	如果异常匹配,则抛出相应的异常,否则最后通过propagate转换为运行时异常。这种方法使得异常处理变得既简洁又清晰。
*/
try {
    // 一些可能抛出多种异常的文件操作
} catch (Exception e) {
    Throwables.throwIfInstanceOf(e, IOException.class);
    Throwables.throwIfInstanceOf(e, SecurityException.class);
    throw Throwables.propagate(e);
}

Guava的Throwables.propagate方法会检查传入的异常是否是运行时异常或错误。如果是,它就直接抛出;如果不是,它会将其包装在一个RuntimeException中,再抛出。

样做的目的是绕过Java的检查型异常机制,使得代码更加灵活。

总结:

  • 谨慎使用异常传播: 虽然Throwables.propagate很方便,但过度使用可能会导致真正的异常原因被掩盖。因此,只在确实需要将检查型异常转为未检查型异常时使用它。
  • 明智使用根本原因分析: getRootCause方法可以帮助找到异常的根本原因,但有时候中间层的异常信息也很重要。所以,在使用这个方法时,要根据具体情况判断。'
  • 保留原始异常信息: 当使用Throwables类处理异常时,要确保原始异常信息不会丢失。这对于后续的问题追踪和修复至关重要。

Throwables与Java 8+的兼容性

Lambda表达式中的异常处理,在Lambda表达式中"偷偷"抛出检查型异常,而不必显式地在Lambda表达式上声明异常。

java 复制代码
List<String> fileNames = ...; // 一些文件名
fileNames.forEach(fileName -> {
    try {
        // 对每个文件名执行某些可能抛出IOException的操作
    } catch (IOException e) {
        throw Throwables.propagate(e);
    }
});

结合Stream API,通过map操作处理每个元素,并利用Throwables来处理可能出现的异常。

java 复制代码
List<String> input = ...; // 输入数据
List<String> processedData = input.stream()
    .map(data -> {
        try {
            // 对数据进行处理,可能抛出异常
            return processData(data);
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    })
    .collect(Collectors.toList());
相关推荐
铁锚7 天前
Guava限频器RateLimiter的使用示例
java·高并发·限流·guava·ratelimiter
-代号952710 天前
不可变集合类型转换异常
java·集合·异常
lingdian2311 天前
限流系列:guava rateLimiter
java·guava·ratelimiter
小呆瓜历险记13 天前
ARM架构
linux·arm开发·架构·异常
蟹至之16 天前
【Java】异常的初步认识
java·开发语言·类和对象·异常
AcmenSan17 天前
深入解析 Guava Cache
java·spring·guava
香吧香1 个月前
Redis 连接池耗尽的一次异常定位
redis·异常
技术liul1 个月前
Spring Boot中集成Guava Cache或者Caffeine
spring boot·spring·guava
东阳马生架构2 个月前
Sentinel源码—5.FlowSlot借鉴Guava的限流算法二
算法·sentinel·guava
〆、风神2 个月前
Guava Cache 实战:构建高并发场景下的字典数据缓存
缓存·guava