如何避免在 java 中捕获 OutOfMemoryError 以及如何解决 class java.lang.OutOfMemoryError cannot be cast to class java.lang.Exception 问题

How to avoid catching OutOfMemoryError in java and how to resolve class java.lang.OutOfMemoryError cannot be cast to class java.lang.Exception issue

for (int i = 0; i <listOfProcesses.size(); i++) {
    try {
        Future<Boolean> futureResult = executorCompletionService.take();
        boolean status = futureResult.get();
    } catch (InterruptedException e) {
        logger.error(e.getMessage());
    } catch (ExecutionException e) {
        logger.error(e.getMessage());
        Exception ex = (Exception)e.getCause();
        if(ex instanceof UncategorizedJmsException) {
            logger.error(e.getMessage());
        } else if(ex instanceof ApplicationException) {
            logger.error(e.getMessage());
        }
    }
}

在执行某些任务时,遇到 OutOfMemory 错误。此异常作为 ExecutionException 被捕获,我得到下面提到的 class 转换异常。

Unexpected error occurred in scheduled task
java.lang.ClassCastException: class java.lang.OutOfMemoryError cannot be cast to class java.lang.Exception 
(java.lang.OutOfMemoryError and java.lang.Exception are in module java.base of loader 'bootstrap')

如何让错误不被转换为异常?为了处理其他springboot异常,我需要通过这种方式转换为异常(Exception)e.getCause()。我如何克服这个 class 强制转换异常?请帮助

您不能将 OutOfMemoryError 转换为 Exception

检查 OutOfMemoryError Doc,你可以看到它不是 Exception 的子 class,而是来自 Error.

并且如 Error Doc 所述:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.

因此您不应尝试捕获 OutOfMemoryError,因为此时您没有太多可用选项来恢复您的应用程序状态。但是可以肯定的是,您不能将 OutOfMemoryError 转换为 Exception,因为这是不可能的。

错误不是异常。

假设您在调用外部服务时得到 OutOfMemoryError,那么您可以在将原因转换为异常之前检查是否存在错误

 catch (ExecutionException e) {
    if (e.getCause() instanceof Error) {
        logger.error("Caught Error");
    } else {
        Exception ex = (Exception)e.getCause();
        if(ex instanceof UncategorizedJmsException) {
            logger.error(e.getMessage());
        } else if(ex instanceof ApplicationException) {
            logger.error(e.getMessage());
        }
    }
}

我将尝试扩展 Panagiotis Bougioukos 的回答。

So you should not try to catch OutOfMemoryError as you don't have much options available

这是真的。这是 Java 的架构师推荐的。在我使用 Java 开发软件近 17 年的时间里,我只需要抓住 OutOfMemoryError 一次。如果 OP 包含有关错误性质的详细信息以了解如何解决这部分问题,那就太好了。就我而言,我正在研究一项使用 Apache POI 打开 Excel 电子表格的功能。该应用程序适用于一家石油和天然气公司,该公司在电子表格上保存了数十年的数据。由于某些遗留 DLL,我们的 Java 应用程序需要与程序的其他部分进行交互,因此该应用程序只能 运行 在 32 位上运行,因此我们的应用程序受到限制。由于这个限制,我决定不要求我们的客户分解这些电子表格,而是捕捉这些错误并尝试以旧 Excel 格式而不是新格式打开文件。这个决定就像一个魅力。

我讲这个故事是为了让您了解这些情况的具体情况:新的 Excel 数据过多,应用程序有 32 位限制,不想用手动数据打扰客户操纵等。对您来说,这里的关键是找出问题的真正根本原因。完成后,尝试通过在应用程序外部修复问题来缓解。例如,也许您没有为 运行 您的代码分配足够的内存。毕竟,在出现此问题之前,我们不知道您的应用程序需要或需要多少最大内存。

如果您查看问题列表并且有足够的缓解情况(如我的情况)证明捕获错误是合理的 AND 您计划在代码是可靠的,然后自行承担风险。正如这里已经说过的,OutOfMemoryError 表示出现了严重错误。因此,通过捕获错误,如果您的替代计划 运行 在某些降级状态下运行您的应用程序并不合理,它甚至可能导致重大问题,例如丢失数据。

处理错误

在我看来,您不应该对您的异常对象创建复杂的“instanceof”询问。如果需要处理特定的异常(或错误),直接处理即可。例如,如果您需要处理内存不足错误,只需在 try/catch

try {
    // execute your process
} catch (OutOfMemoryError error) {
    // execute alternate process
}

try 的主体应该尽可能小,如果您知道的话,会导致该条件的代码行。