@Beta // TODO(kevinb): decide best return type
  public static List<Throwable> getCausalChain(Throwable throwable) {
    checkNotNull(throwable);
    List<Throwable> causes = new ArrayList<>(4);
    causes.add(throwable);

    // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
    // the slower pointer, then there's a loop.
    Throwable slowPointer = throwable;
    boolean advanceSlowPointer = false;

    Throwable cause;
    while ((cause = throwable.getCause()) != null) {
      throwable = cause;
      causes.add(throwable);

      if (throwable == slowPointer) {
        throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
      }
      if (advanceSlowPointer) {
        slowPointer = slowPointer.getCause();
      }
      advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
    }
    return Collections.unmodifiableList(causes);
  }
@Beta 
  public static List<Throwable> getCausalChain(Throwable throwable) {
    checkNotNull(throwable);
    List<Throwable> causes = new ArrayList<>(4);
    causes.add(throwable);

    
    
    Throwable slowPointer = throwable;
    boolean advanceSlowPointer = false;

    Throwable cause;
    while ((cause = throwable.getCause()) != null) {
      throwable = cause;
      causes.add(throwable);

      if (throwable == slowPointer) {
        throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
      }
      if (advanceSlowPointer) {
        slowPointer = slowPointer.getCause();
      }
      advanceSlowPointer = !advanceSlowPointer; 
    }
    return Collections.unmodifiableList(causes);
  }
@ Beta // TODO(kevinb): decide best return type public static List < Throwable > getCausalChain ( Throwable throwable ) { checkNotNull ( throwable ) ; List < Throwable > causes = new ArrayList <> ( 4 ) ; causes . add ( throwable ) ; // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches // the slower pointer, then there's a loop. Throwable slowPointer = throwable ; boolean advanceSlowPointer = false ; Throwable cause ; while ( ( cause = throwable . getCause ( ) ) != null ) { throwable = cause ; causes . add ( throwable ) ; if ( throwable == slowPointer ) { throw new IllegalArgumentException ( "Loop in causal chain detected." , throwable ) ; } if ( advanceSlowPointer ) { slowPointer = slowPointer . getCause ( ) ; } advanceSlowPointer = ! advanceSlowPointer ; // only advance every other iteration } return Collections . unmodifiableList ( causes ) ; }
Gets a {@code Throwable} cause chain as a list. The first entry in the list will be {@code
throwable} followed by its cause hierarchy. Note that this is a snapshot of the cause chain and
will not reflect any subsequent changes to the cause chain.

<p>Here's an example of how it can be used to find specific types of exceptions in the cause
chain:

<pre>
Iterables.filter(Throwables.getCausalChain(e), IOException.class));
</pre>

@param throwable the non-null {@code Throwable} to extract causes from
@return an unmodifiable list containing the cause chain starting with {@code throwable}
@throws IllegalArgumentException if there is a loop in the causal chain
Gets a { @code Throwable } cause chain as a list . The first entry in the list will be { @code throwable } followed by its cause hierarchy . Note that this is a snapshot of the cause chain and will not reflect any subsequent changes to the cause chain .