Is it possible to use Streams.intRange function?

旧城冷巷雨未停 提交于 2019-12-19 10:52:21

问题


I wanted to use Streams.intRange(int start, int end, int step) to achieve reverse ordered stream. However it seems that java.util.Streams class is no longer available (however it is still in rt.jar in standard library). Is this method in some other class or replaced with something else?


回答1:


There is indeed no such method anymore in the JDK; the next closest you could get is IntStream.range() but that will only step one by one.

One solution here would be to implement your own Spliterator.OfInt; for instance something like this (VERY CRUDE; can be improved!):

public final class StepRange
    implements Spliterator.OfInt
{
    private final int start;
    private final int end;
    private final int step;

    private int currentValue;

    public StepRange(final int start, final int end, final int step)
    {
        this.start = start;
        this.end = end;
        this.step = step;
        currentValue = start;
    }

    @Override
    public OfInt trySplit()
    {
        return null;
    }

    @Override
    public long estimateSize()
    {
        return Long.MAX_VALUE;
    }

    @Override
    public int characteristics()
    {
        return Spliterator.IMMUTABLE | Spliterator.DISTINCT;
    }

    @Override
    public boolean tryAdvance(final IntConsumer action)
    {
        final int nextValue = currentValue + step;
        if (nextValue > end)
            return false;
        action.accept(currentValue);
        currentValue = nextValue;
        return true;
    }
}

You would then use StreamSupport.intStream() to generate your stream from an instance of the class above.




回答2:


Both solutions proposed so far don't respect parallelization. The spliterator proposed by @fge does not parallelize at all. The iterate-based stream proposed by @RealSkeptic will use buffered parallelization (some numbers will be loaded into the intermediate array and handed over to the another thread) which is not always effective.

There's quite simple alternative solution which provides normal parallelization (here end is exclusive):

public static IntStream intRange(int start, int end, int step ) {
    int limit = (end-start+step-(step>>31|1))/step;
    return IntStream.range(0, limit).map(x -> x * step + start);
}

Or if you want to take into account really weird inputs like intRange(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE):

public static IntStream intRange(int startInclusive, int endExclusive, int step) {
    if(step == 0)
        throw new IllegalArgumentException("step = 0");
    if(step == 1)
        return IntStream.range(startInclusive, endExclusive);
    if(step == -1) {
        // Handled specially as number of elements can exceed Integer.MAX_VALUE
        int sum = endExclusive+startInclusive;
        return IntStream.range(endExclusive, startInclusive).map(x -> sum - x);
    }
    if((endExclusive > startInclusive ^ step > 0) || endExclusive == startInclusive)
        return IntStream.empty();
    int limit = (endExclusive-startInclusive)*Integer.signum(step)-1;
    limit = Integer.divideUnsigned(limit, Math.abs(step));
    return IntStream.rangeClosed(0, limit).map(x -> x * step + startInclusive);
}



回答3:


You can create it based on an infinite stream:

public static IntStream intRange(int start, int end, int step ) {
    if ( step == 0 ) {
        throw new IllegalArgumentException("Cannot iterate with a step of zero");
    }
    final int limit = (end - start + step) / step;
    if ( limit < 0 ) {
        return IntStream.empty();
    }
    return IntStream.iterate(start, x -> x + step )
                    .limit( limit );
}

If the range doesn't make sense (e.g. range from 7 to 2 in steps of 1) you get an empty stream.

The limit is inclusive. That is, range from 2 to 8 in steps of 2 will give you 2,4,6,8. If you want it to be exclusive (without the 8), change the limit to:

final int limit = (end - start) / step;

Possible usage:

intRange(8 ,2, -2).forEach(System.out::println);

Output:

8
6
4
2


来源:https://stackoverflow.com/questions/32586604/is-it-possible-to-use-streams-intrange-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!