是否可以使用Streams.intRange函数?

我想使用Streams.intRange(int start,int end,int step)来实现反向排序流。 但是,似乎java.util.Streams类不再可用(但它仍然在标准库中的rt.jar中)。 这个方法是在其他类中还是用其他类替换?

在JDK中确实没有这样的方法; 你可以得到的下一个最接近的是IntStream.range()但这只是逐个步骤。

这里的一个解决方案是实现自己的Spliterator.OfInt ; 比如像这样的东西(非常粗糙;可以改进!):

 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; } } 

然后,您将使用StreamSupport.intStream()从上面的类的实例生成流。

到目前为止提出的两种解决方案都不尊重并行化。 @fge提出的分裂器根本不是并行化的。 @RealSkeptic提出的基于迭代的流将使用缓冲并行化(一些数字将被加载到中间数组并移交给另一个线程),这并不总是有效的。

有一个非常简单的替代解决方案,提供正常的并行化(这里end是独家的):

 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); } 

或者,如果您想要考虑非常奇怪的输入,如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); } 

您可以基于无限流创建它:

 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 ); } 

如果范围没有意义(例如,以1为单位从7到2的范围),则会得到一个空流。

限制是包容性的。 也就是说,2到2的范围从2到8将给你2,4,6,8。 如果您希望它是独占的(没有8),请将限制更改为:

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

可能的用法:

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

输出:

 8 6 4 2