In Java 9, you would probably use
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
return Stream.iterate(type, Objects::nonNull, Class::getSuperclass);
}
but in Java 8, this feature is not available, so you may resort to implement the Stream manually:
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<Class<?>>(100L,
Spliterator.ORDERED|Spliterator.IMMUTABLE|Spliterator.NONNULL) {
Class<?> current = type;
public boolean tryAdvance(Consumer<? super Class<?>> action) {
if(current == null) return false;
action.accept(current);
current = current.getSuperclass();
return true;
}
}, false);
}
Note that this will stream from the most specific type towards java.lang.Object
. If you want the order to be from Object
to the most specific one, there is no way around gathering the elements first, whether recursive or iterative, is not so important, but Stream.concat
is indeed the least performance variant. You can simply use
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
return reverse(Stream.<Class<?>>builder(), type, Class::getSuperclass).build();
}
private static <T> Stream.Builder<T> reverse(
Stream.Builder<T> builder, T t, UnaryOperator<T> op) {
return t==null? builder: reverse(builder, op.apply(t), op).add(t);
}
The iterative variant also is not so bad:
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
List<Class<?>> l=new ArrayList<>();
for(; type!=null; type=type.getSuperclass()) l.add(type);
Collections.reverse(l);
return l.stream();
}
For streams as small as a typical class hierarchy, an ArrayList
is not worse than a Stream.Builder
and for very large streams, filling the builder using a recursion might not be the best solution either…