问题
I would like to convert the following for
statement to a Java 8 stream (i.e. Stream<Class<?>>
). The ideal solution would be simple enough that I can easily adapt it for a variety of situations of traversing a linked list (e.g. File.getParentFile()
, Component.getParent()
).
Class<?> clazz;
Object value;
value = ...;
for (clazz = value.getClass(); clazz != null; clazz = clazz.getSuperclass())
...
I realize that a few lines of code to create a stream isn't going to be simpler than a single for
statement. However, a stream makes the body of the for
loop simpler and hence a stream is desirable.
回答1:
You need a takeWhile method which will appear in JDK-9 only. Currently you can use a back-port which is available, for example, in my StreamEx library:
Stream<Class<?>> stream = StreamEx.iterate(value.getClass(), Class::getSuperClass)
.takeWhile(Objects::nonNull);
In JDK-9 just replace StreamEx
with Stream
.
回答2:
Here's the same code as presented in the question but implemented using a Spliterator
. I am hoping someone can come up with a simpler, smarter answer.
Class<?> clazz;
Object value;
value = ...;
<Class<?>>walkLinks(value.getClass(), Class::getSuperclass).
...
public static <T> Stream<T> walkLinks(T start, Function<T, T> next)
{
WalkLinks<T> walker;
Stream<T> result;
walker = new WalkLinks<>(start, next);
result = StreamSupport.stream(walker, false);
return(result);
}
private static class WalkLinks<T> extends Spliterators.AbstractSpliterator<T>
{
private final Function<T, T> m_next;
private T m_value;
public WalkLinks(T value, Function<T, T> next)
{
super(Long.MAX_VALUE, Spliterator.ORDERED + Spliterator.NONNULL);
m_value = value;
m_next = next;
}
@Override
public boolean tryAdvance(Consumer<? super T> action)
{
if (m_value == null)
return(false);
action.accept(m_value);
m_value = m_next.apply(m_value);
return(true);
}
}
来源:https://stackoverflow.com/questions/34956701/java-8-stream-of-super-classes-parent-files-component-parents-linked-list-et