是否有更好的(java8?)方式来收集"导致堆栈"异常?

时间:2017-08-23 18:30:27

标签: java exception java-8

我们的项目中有一个BaseException extends Exception,基本上所有其他异常都来自这个类。我想改变一些处理"导致堆栈"的方法。在运行时。

作为起点,我写了以下方法:

class BaseException extends Exception {
...

  /**
   * Helper: creates a list containing the complete "cause stack" of this exception.
   * Please note: the exception on which this method is called is part of result!
   *
   * @return a {@link List} of all "causes" of this exception 
   */
  List<Throwable> getAllCauses() {
    Throwable cause = this;
    List<Throwable> causes = new ArrayList<>();
    while (cause != null) {
      causes.add(cause);
      cause = cause.getCause();
    }          
    return causes;
  }

这可以完成工作,虽然它并不完美(名称并不完美,并且也违反了单层抽象)。

但仍然:是否有更优雅的#34;收集这个结果的方法?特别是考虑到直接返回Stream<Throwable>会有帮助的事实。

(我主要想知道是否有一个java8 lambda / idiom可以帮助到这里)

3 个答案:

答案 0 :(得分:10)

This文章应该有所帮助。特别是,

Stream<Throwable> causes(Throwable t){
    if (t == null) return Stream.empty();
    return Stream.concat(Stream.of(t), causes(t.getCause()));
}

答案 1 :(得分:4)

以下是我Spliterator实施的实施方式,如下所示:

public static <T> Stream<T> 
       iterateUntil(T seed, UnaryOperator<T> generator, Predicate<T> proceed){
  return stream(new AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED){
    private T value = seed;
    public boolean tryAdvance(Consumer<? super T> action){
      if(!proceed.test(value)) return false;
      action.accept(value);
      value = generator.apply(value);
      return true;
    }
  }, false);
}

然后你可以实现你的getCauses,如下所示,它会丢弃递归调用:

List<Throwable> getAllCauses() {
    return iterateUntil(this, Throwable::getCause, Objects::nonNull)
              .collect(toList());
}

答案 2 :(得分:1)

使用一些枚举似乎更适合我,然后像

class BaseException extends Exception {
...

  Enumeration<Throwable> getCauses() {
    return new Enumeration<Throwable>() {
       private Throwable current = BaseException.this;
       public boolean hasMoreElements() {
         return current != null;
       }
       public Throwable nextElement() {
         Throwable c = current;
         current = current.getCause();
         return c;
       }
    }
  }

使用Java 8,您还可以使用默认方法创建一个新接口,然后在任何异常类中使用该接口(稍微好于子类化Exception?)。