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?
The problem is the missing stop condition in
Stream.iterate
. In Java 9, you could usewhich is equivalent to Java 9’s
See
Stream.iterate
orStream.takeWhile
.Since this feature does not exist in Java 8, a back-port would be required:
The semantic is the same as with Java 9’s
Stream.iterate
:The recursive
Stream::concat()
approach creates the entire stream in advance in one recursive call. The lazytakeWhile
approach is not available until Java 9.The following is a lazy, Java 8 approach:
Usage:
Update: Replacing
Iterator
/Iterable.spliterator()
with direct construction of aSpliterator
:Update 2:
For a one-off, efficient, minimal-code implementation that converts the chain of
Throwable
objects into aStream<Throwable>
stream, and immediately using said stream:This has the disadvantage of being non-lazy (traversing the entire chain at stream construction time), but avoids the inefficiencies of recursion and Stream.concat().
I have another option via a
Spliterator
:What exactly is wrong with this?
There is no point in being "more functional." Functional style is just a tool, and it's clearly inappropriate here.
If I understand you correctly, you can create a
Stream
with seedroot
(your headThrowable
in linkedlist). AsUnaryOperator
take is the nextThrowable
. Example:I think that you can do a recursive call here: