Ari*_*ion 19 java collections java-8 java-stream
我想迭代堆栈跟踪.stacktrace由throwables组成,其getCause()返回下一个throwable.对getCause()的最后一次调用返回null.(示例:a - > b - > null)
我试图使用Stream.iterable()导致NullPointerException,因为iterable中的元素不能为null.以下是该问题的简短演示:
public void process() {
Throwable b = new Throwable();
Throwable a = new Throwable(b);
Stream.iterate(a, Throwable::getCause).forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)
我目前正在使用while循环手动创建集合:
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);
}
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法(更短,更实用)来实现这一目标?
Hol*_*ger 16
问题是缺少停止条件Stream.iterate.在Java 9中,您可以使用
Stream.iterate(exception, Objects::nonNull, Throwable::getCause)
Run Code Online (Sandbox Code Playgroud)
这相当于Java 9的
Stream.iterate(exception, Throwable::getCause)
.takeWhile(Objects::nonNull)
Run Code Online (Sandbox Code Playgroud)
见Stream.iterate或Stream.takeWhile.
由于Java 8中不存在此功能,因此需要后端口:
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);
}
Run Code Online (Sandbox Code Playgroud)
语义与Java 9相同Stream.iterate:
MyStreamFactory.iterate(exception, Objects::nonNull, Throwable::getCause)
.forEach(System.out::println); // just an example
Run Code Online (Sandbox Code Playgroud)
Eug*_*ene 14
我想你可以在这里做一个递归调用:
static Stream<Throwable> process(Throwable t) {
return t == null ? Stream.empty() : Stream.concat(Stream.of(t), process(t.getCause()));
}
Run Code Online (Sandbox Code Playgroud)
递归Stream::concat()方法在一次递归调用中预先创建整个流.takeWhile直到Java 9才能使用惰性方法.
以下是一个懒惰的Java 8方法:
class NullTerminated {
public static <T> Stream<T> stream(T start, Function<T, T> advance) {
Iterable<T> iterable = () -> new Iterator<T>() {
T next = start;
@Override
public boolean hasNext() {
return next != null;
}
@Override
public T next() {
T current = next;
next = advance.apply(current);
return current;
}
};
return StreamSupport.stream(iterable.spliterator(), false);
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
Throwable b = new Throwable();
Throwable a = new Throwable(b);
NullTerminated.stream(a, Throwable::getCause).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
更新:更换Iterator/ Iterable.spliterator()直接构建Spliterator:
class NullTerminated {
public static <T> Stream<T> stream(T start, Function<T, T> advance) {
Spliterator<T> sp = new AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.NONNULL) {
T current = start;
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (current != null) {
action.accept(current);
current = advance.apply(current);
return true;
}
return false;
}
};
return StreamSupport.stream(sp, false);
}
}
Run Code Online (Sandbox Code Playgroud)
更新2:
对于一次性,高效,最小化的代码实现,它将Throwable对象链转换为Stream<Throwable>流,并立即使用所述流:
Stream.Builder<Throwable> builder = Stream.builder();
for(Throwable t = a; t != null; t = t.getCause())
builder.accept(t);
builder.build().forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是非延迟(在流构建时遍历整个链),但避免了递归和Stream.concat()的低效率.
我有另一种选择Spliterator:
static Stream<Throwable> process(Throwable t) {
Spliterator<Throwable> sp = new AbstractSpliterator<Throwable>(100L, Spliterator.ORDERED) {
Throwable inner = t;
@Override
public boolean tryAdvance(Consumer<? super Throwable> action) {
if (inner != null) {
action.accept(inner);
inner = inner.getCause();
return true;
}
return false;
}
};
return StreamSupport.stream(sp, false);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
811 次 |
| 最近记录: |