I want to iterate over a stacktrace. The stacktrace consists of throwables whose getCause() returns the next throwable. The last call to getCause() returns null. (Example: a -> b -> null)
I've tried to use Stream.iterable() which results in a NullPointerException, since the elements in the iterable can't be null. Here is a short demonstration of the problem:
public void process() {
Throwable b = new Throwable();
Throwable a = new Throwable(b);
Stream.iterate(a, Throwable::getCause).forEach(System.out::println);
}
I'm currently using a while loop to create a collection manually:
public void process() {
Throwable b = new Throwable();
Throwable a = new Throwable(b);
List<Throwable> list = new ArrayList<>();
Throwable element = a;
while (Objects.nonNull(element)) {
list.add(element);
element = element.getCause();
}
list.stream().forEach(System.out::println);
}
Is there a better way (shorter, more functional) to achieve this?
stream(). mapToInt(AClass::getValue).
A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. The features of Java stream are – A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.
The problem is the missing stop condition in Stream.iterate
. In Java 9, you could use
Stream.iterate(exception, Objects::nonNull, Throwable::getCause)
which is equivalent to Java 9’s
Stream.iterate(exception, Throwable::getCause)
.takeWhile(Objects::nonNull)
See Stream.iterate
or Stream.takeWhile
.
Since this feature does not exist in Java 8, a back-port would be required:
public static <T> Stream<T>
iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
{
Objects.requireNonNull(next);
Objects.requireNonNull(hasNext);
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
T current = seed;
int state;
public boolean tryAdvance(Consumer<? super T> action) {
Objects.requireNonNull(action);
T value = current;
if(state > 0) value = next.apply(value);
else if(state == 0) state = 1;
else return false;
if(!hasNext.test(value)) {
state = -1;
current = null;
return false;
}
action.accept(current = value);
return true;
}
},
false);
}
The semantic is the same as with Java 9’s Stream.iterate
:
MyStreamFactory.iterate(exception, Objects::nonNull, Throwable::getCause)
.forEach(System.out::println); // just an example
I think that you can do a recursive call here:
static Stream<Throwable> process(Throwable t) {
return t == null ? Stream.empty() : Stream.concat(Stream.of(t), process(t.getCause()));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With