我正在慢慢学习新的Java 8功能,我正在尝试找到一种方法来处理类层次结构(从子级到父级)作为流。
例如,在类或它的父类上查找注释。
在Java 8之前,我会这样做:
public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) {
Class<?> t = type;
T annot = null;
while (t != null && annot == null) {
annot = t.getAnnotation(annType);
t = t.getSuperclass();
}
return annot;
}
现在我希望以更多“功能性编程”方式来实现。 我找不到一个更好的方法,而不是像递归一样连接流:
import java.lang.annotation.Annotation;
import java.util.stream.Stream;
public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) {
return ClassIterator.streamSuperclass(type)
.map(t -> t.getAnnotation(annType))
.filter(a -> a != null)
.findFirst()
.orElse(null);
}
public static class ClassIterator {
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
if (type.getSuperclass() != null) {
return Stream.concat(Stream.of(type), Stream.of(type.getSuperclass()).flatMap(ClassIterator::streamSuperclass));
}
return Stream.of(type);
}
}
但我对解决方案不太满意。虽然我没有对它进行基准测试,但我认为流连接非常麻烦并且性能很差。
有没有更好的方法将递归转换为流?
答案 0 :(得分:4)
在Java 9中,您可能会使用
public static Stream<Class<?>> streamSuperclass(Class<?> type) {
return Stream.iterate(type, Objects::nonNull, Class::getSuperclass);
}
但是在Java 8中,此功能不可用,因此您可以手动实现Stream:
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);
}
请注意,这会从最具体的类型流向java.lang.Object
。如果您希望订单从Object
到最具体的订单,则无法首先收集元素,无论是递归还是迭代,都不是那么重要,但Stream.concat
确实是性能最差的变种。你可以简单地使用
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);
}
迭代变体也不是那么糟糕:
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();
}
对于像典型类层次结构一样小的流,ArrayList
并不比Stream.Builder
差,对于非常大的流,使用递归填充构建器可能不是最佳解决方案...... < / p>