注意Java 8的[Pri​​mitive] Stream.iterate()中的递归

Tagir Valeev关于Stack Overflow的一个有趣问题最近引起了我的注意。 为了简短起见(请阅读问题的详细信息),而以下代码则有效:

public static Stream<Long> longs() {
    return Stream.iterate(1L, i ->
        1L + longs().skip(i - 1L)
                    .findFirst()
                    .get());
}

longs().limit(5).forEach(System.out::println);

印刷

1
2
3
4
5

以下类似代码将不起作用:

public static LongStream longs() {
    return LongStream.iterate(1L, i ->
        1L + longs().skip(i - 1L)
                    .findFirst()
                    .getAsLong());
}

导致StackOverflowError

当然,这种递归迭代不是最佳的。 它不是Java 8之前的版本,当然也没有新的API。 但是有人可能认为它至少应该起作用,对吗? 之所以不起作用,是因为Java 8中的两个iterate()方法之间的细微实现差异。虽然引用类型流的Iterator首先返回seed ,然后才通过将迭代函数应用于前一个继续进行迭代。值:

final Iterator<T> iterator = new Iterator<T>() {
    @SuppressWarnings("unchecked")
    T t = (T) Streams.NONE;

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public T next() {
        return t = (t == Streams.NONE) ? seed : f.apply(t);
    }
};

LongStream.iterate()版本(和其他原始流)不是这种情况:

final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
    long t = seed;

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public long nextLong() {
        long v = t;
        t = f.applyAsLong(t);
        return v;
    }
};

迭代功能已预先预取一个值。 这通常不是问题,但可能导致

  1. 迭代函数昂贵时的优化问题
  2. 递归使用迭代器时的无限递归

作为一种解决方法,最好避免在原始类型流中使用此方法简单地进行递归。 幸运的是,JDK 9中的修复已在进行中(作为功能增强的副作用): https : //bugs.openjdk.java.net/browse/JDK-8072727

翻译自: https://www.javacodegeeks.com/2016/03/watch-recursion-java-8s-primitivestream-iterate.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值