【问题标题】:Java8 Streaming a class hierarchy [duplicate]Java8流式传输类层次结构[重复]
【发布时间】:2016-10-25 12:50:26
【问题描述】:

我正在慢慢学习 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);
    }
}

但我对解决方案不太满意。虽然我没有对其进行基准测试,但我认为流连接非常麻烦且性能不佳。

有没有更好的方法将递归变成流?

【问题讨论】:

  • 本质上,您正在寻找takeWhile(遍历超类并在它不为空时获取),请参阅stackoverflow.com/questions/20746429/…
  • takeWhile() 出现在 Java 9 中。此外,Stream.iterate() 的 3-arg 版本,可以模拟 for 样式的循环。

标签: reflection java-8 java-stream


【解决方案1】:

在 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 差,对于非常大的流,使用递归填充构建器可能也不是最佳解决方案……

【讨论】:

    猜你喜欢
    • 2015-08-12
    • 2016-11-13
    • 2020-07-17
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2022-01-26
    相关资源
    最近更新 更多