通过自引用迭代对象

时间:2016-08-26 19:54:58

标签: java java-8 java-stream

假设我们有一个对象A,它包含一定数量的特定年份。该对象还引用了同一类的另一个对象,该对象保存与前一年相关的数据。

是否有可能使用Java流生成所有这些对象的列表(当前年份,previos,previos去年...)?

祝你好运

2 个答案:

答案 0 :(得分:2)

由于JDK 9中提供了takeWhile操作,您可以实现自己的Iterator<T>并将其转换为Stream<T>,例如:

private static <T> Stream<T> iterate(T root, UnaryOperator<T> generator, Predicate<T> stop) {
  return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<T>() {
    private T t = root;

    @Override
    public boolean hasNext() {
      return stop.test(t);
    }

    @Override
    public T next() {
      T result = t;
      t = generator.apply(t);
      return result;
    }
  }, Spliterator.IMMUTABLE | Spliterator.ORDERED), false);
}

用法可能如下:

Stream<A> s = iterate(root, t -> t.next, Objects::nonNull);

答案 1 :(得分:1)

如果必须使用Stream API完成,那么这是一种潜在的方法。它假设最后一个对象A在其对前一年的引用中将具有null,因此谓词 - elem -> elem != null。如果它不为null或某种A.NULL对象,则只需相应地修改谓词。

import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class Test {

    public static void main(String[] args) {
        A a = new A(2016);
        a.prev = new A(2015);
        a.prev.prev = new A(2014);
        a.prev.prev.prev = new A(2013);

        // .. etc

        List<A> list = takeWhile(Stream.iterate(a, elem -> elem.prev),
                elem -> elem != null)
                .collect(Collectors.toList());

        // this prints - 2016, 2015, 2014, 2013
        System.out.println(list);
    }

    /**
     * This has been taken from this SO answer:
     * http://stackoverflow.com/questions/20746429/limit-a-stream-by-a-predicate
     */
    static <T> Spliterator<T> takeWhile(
            Spliterator<T> splitr, Predicate<? super T> predicate) {
        return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
            boolean stillGoing = true;
            @Override public boolean tryAdvance(Consumer<? super T> consumer) {
                if (stillGoing) {
                    boolean hadNext = splitr.tryAdvance(elem -> {
                        if (predicate.test(elem)) {
                            consumer.accept(elem);
                        } else {
                            stillGoing = false;
                        }
                    });
                    return hadNext && stillGoing;
                }
                return false;
            }
        };
    }

    static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
        return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
    }

    static class A {

        A prev;
        int year;
        // some other data

        public A(int year) {
            this.year = year;
        }

        @Override
        public String toString() {
            return year + "";
        }
    }
}