37

我需要检查异常是否是由某些数据库问题引起的。我收到一个异常并检查其原因是否包含“ORA”字符串并返回(类似于“ORA-00001”)。这里的问题是我收到的异常嵌套在其他异常中,所以如果我不知道它是否是 oracle 异常,我必须检查该异常的原因等等。有没有更清洁的方法来做到这一点?有没有办法知道给定异常的第一个原因(深层嵌套异常)?

我当前的代码如下所示:

private String getErrorOracle(Throwable e){
        final String ORACLE = "ORA";
        if (e.getCause() != null && e.getCause().toString().contains(ORACLE)){
            return e.getCause().toString();
        } else if(e.getCause() != null){
            return getErrorOracle(e.getCause());
        } else {
            return null;
        }
    }
4

13 回答 13

87

为了不重新发明轮子,如果您使用的是Apache Commons Lang,请查看ExceptionUtils.getRootCause()

是否值得为此包括一个图书馆?也许不吧。但是如果你已经在你的类路径中拥有它,它就在那里,并注意它做了一些“天真的”实现可能不会做的事情(例如处理原因链中的循环......呃!)

于 2009-11-25T00:20:25.970 回答
18

如果你已经在Guava上,那么Throwables.getRootCause()会来救援。

于 2013-05-11T15:10:13.273 回答
15

只需遍历异常链,直到您无缘无故地遇到异常,然后返回该消息,如果您想要最后一个。

你的函数只会得到第一个原因,如果有的话。

不过,您可能希望查看包中的第一个原因,因为实际最深的原因可能是 oracle 异常,这很有帮助,但除非您能看到问题是在哪里造成的,否则您将很难修复它。

于 2009-11-24T17:31:57.137 回答
4

可能对您的使用有点矫枉过正,但我​​认为它更清洁(并且可重复使用)

interface ThrowablePredicate {
    boolean accept(Throwable t);
}

public OracleErrorThrowablePredicate implements ThrowablePredicate {
    private static final ORA_ERR = "ORA";

    public boolean accept(Throwable t) {
        return t.toString().contains(ORA_ERR);
    }
}


public class CauseFinder {

   private ThrowablePredicate predicate;

   public CauseFinder(ThrowablePredicate predicate) {
      this.predicate = predicate;
   }

   Throwable findCause(Throwable t) {
      Throwable cause = t.getCause();

      return cause == null ? null 
         : predicate.accept(cause) ? cause : findCause(cause)
   }
}


// Your method
private String getErrorOracle(Throwable e){
    return new CauseFinder(new OracleErrorThrowablePredicate()).findCause(e);
}
于 2009-11-24T17:45:43.987 回答
2

我认为 oracle 抛出的任何错误都将包含在 SQLException 中(如果错误,请有人纠正我)。访问 SQLException 后,您应该可以调用

getErrorCode() 检索此 SQLException 对象的特定于供应商的异常代码。

让我知道这是否有效,因为我从未尝试过:-)

卡尔

于 2009-11-24T17:37:35.830 回答
2

您可以改进对SQLException的代码检查

import java.sql.SQLException;

private static final String ORACLE = "ORA";

public String doHandle(Throwable t) {
    if (t.getClass().isAssignableFrom(SQLException.class)) {
    SQLException e = (SQLException) t;
    int errCode = e.getErrorCode();
    String state = e.getSQLState();
    String msg = e.getMessage();
    if (msg.contains(ORACLE)) {
        return msg;
        }
    } else {
        if (t.getCause() != null) {
            return this.doHandle(t.getCause());
            }
        }
    return "";
}

另外,我认为在 Oracle 中“errCode”包含与 ORA-nnnn 关联的数字

于 2009-11-24T17:45:09.307 回答
0

您可以使用 Throwable 类中的getStackTrace()。这将为您提供可使用的 StackTraceElements 堆栈。您可以遍历 StackTraceElements[] 以找到“ORA”字符串。

如果你需要一个例子,请告诉我。

于 2009-11-24T17:33:01.690 回答
0

使用核心 Java API 的一条线解决方案:

    try {
        i = 1 / 0; 
    } catch (ArithmeticException e) {
        System.out.println(new ArithmeticException().initCause(e).getCause());
    }

下面的另一种解决方案也有效:

    try {
        i = 1 / 0; 
    } catch (ArithmeticException e) {
        System.out.println(new Exception().initCause(e).getCause());
    }

他们都将打印

java.lang.ArithmeticException: / 由零

于 2020-08-18T03:50:40.590 回答
0

getRootCause在我的IDEA的 Spring Boot 项目中建议 3 静态导入:

Spring Core:org.springframework.core.NestedExceptionUtils.getRootCause
杰克逊:com.fasterxml.jackson.databind.util.ClassUtil.getRootCause
番石榴(Swagger 传递)com.google.common.base.Throwables.getRootCause

最聪明的(带有循环检查)是 Spring NestedExceptionUtils.getRootCause。但是,如果您的异常没有原因,则方法返回null。就我而言,这是错误的,所以我做了:

@NonNull
public static Throwable getRootCause(@NonNull Throwable t) {
    Throwable rootCause = NestedExceptionUtils.getRootCause(t);
    return rootCause != null ? rootCause : t;
}
于 2020-12-24T19:10:22.983 回答
0

我想添加 Kotlin 扩展函数来获取根本原因:

fun Throwable.rootCause(): Throwable {
  return if (cause == null) this else cause!!.rootCause()
}

//Return null if first cause is null
fun Throwable.optRootCause(): Throwable? {
  return if (cause == null) null else cause!!.rootCause()
}

或者这个如果需要在任何时候在可投掷链中找到原因:

fun <T : Throwable> Throwable.isOrContainsCauseOfType(clazz: KClass<T>): Throwable?  {
  return when {
    clazz.isInstance(this) -> this //remove if you want to exclude [this]
    cause == null -> null
    clazz.isInstance(cause) -> cause
    else -> cause!!.isOrContainsCauseOfType(clazz)
  }
}
于 2021-09-03T16:10:39.243 回答
0

ExceptionUtils.getRootCause()Throwables.getRootCause()如果传递的异常的原因为 null,则返回 null。如果将没有原因的 throwable 作为输入参数传递,则以下方法将返回原始 throwable。

/**
 * @return the root cause of a given throwable.
 *   If throwable without a cause is being passed, the original throwable will be returned
 */
public static Throwable getRootCause(@NonNull final Throwable throwable) {
    List<Throwable> throwableList = ExceptionUtils.getThrowableList(throwable);
    return throwableList.get(throwableList.size() - 1);
}
于 2022-02-17T07:34:05.707 回答
-1

如果抛出的异常总是属于特定类型,如 OracleException,您可以只捕获该异常。

例如:

try {

    ...

} catch(OracleException oe) {

    ...

}

这仅适用于抛出特定 Oracle 异常的情况。我对 Oracle 了解不多,因此在尝试此操作之前,您可能想知道是否发生了这种情况。

于 2009-11-24T17:40:30.567 回答
-2

在 28-01-2015,我无法使用上述任何解决方案解决我的问题,所以我的建议是使用:

e.getMessage().toString();

Ps:我在安卓上使用它。

于 2016-01-28T07:10:06.977 回答