一般问题:什么是反转流的正确方法?假设我们不知道流由什么类型的元素组成,反转任何流的通用方法是什么?

具体问题:

IntStream提供了在特定范围内生成整数的range方法。range(-range, 0),现在我想反转它,从0到负切换范围将不起作用,我也不能使用Integer::比较

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);

使用IntStream,我将得到这个编译器错误

错误:(191,0)ajc: IntStream类型中的sorted()方法不适用于参数(Integer::compare)

我错过了什么?


当前回答

反转流的正确通用方法是什么?

如果流没有指定遇到顺序,就不要这样做。 (! s.spliterator () .hasCharacteristics (java.util.Spliterator.ORDERED))

其他回答

一般问题:

流不存储任何元素。

因此,如果不将元素存储在某个中间集合中,就不可能以相反的顺序迭代元素。

Stream.of("1", "2", "20", "3")
      .collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList
      .descendingIterator()
      .forEachRemaining(System.out::println);

更新:改变LinkedList为ArrayDeque(更好),详情请看这里

打印:

3

20

2

1

顺便说一下,使用sort方法是不正确的,因为它排序,而不是反转(假设流可能有无序元素)

具体问题:

我发现这很简单,更容易和直观(复制@Holger评论)

IntStream.iterate(to - 1, i -> i - 1).limit(to - from)

cyclops-react StreamUtils有一个反向流方法(javadoc)。

  StreamUtils.reverse(Stream.of("1", "2", "20", "3"))
             .forEach(System.out::println);

它的工作原理是收集到一个数组列表,然后使用可以向任意方向迭代的ListIterator类,在列表上向后迭代。

如果你已经有了一个List,它会更有效率

  StreamUtils.reversedStream(Arrays.asList("1", "2", "20", "3"))
             .forEach(System.out::println);

Java 8的方法:

    List<Integer> list = Arrays.asList(1,2,3,4);
    Comparator<Integer> comparator = Integer::compare;
    list.stream().sorted(comparator.reversed()).forEach(System.out::println);

这里的许多解决方案对IntStream进行排序或反转,但这不必要地需要中间存储。斯图尔特·马克斯的解决方案是可行的:

static IntStream revRange(int from, int to) {
    return IntStream.range(from, to).map(i -> to - i + from - 1);
}

它正确地处理溢出以及,通过这个测试:

@Test
public void testRevRange() {
    assertArrayEquals(revRange(0, 5).toArray(), new int[]{4, 3, 2, 1, 0});
    assertArrayEquals(revRange(-5, 0).toArray(), new int[]{-1, -2, -3, -4, -5});
    assertArrayEquals(revRange(1, 4).toArray(), new int[]{3, 2, 1});
    assertArrayEquals(revRange(0, 0).toArray(), new int[0]);
    assertArrayEquals(revRange(0, -1).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MAX_VALUE, MAX_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE});
    assertArrayEquals(revRange(MAX_VALUE - 1, MAX_VALUE).toArray(), new int[]{MAX_VALUE - 1});
}

关于生成反向IntStream的具体问题:

从Java 9开始,你可以使用三个参数版本的IntStream.iterate(…):

IntStream.iterate(10, x -> x >= 0, x -> x - 1).forEach(System.out::println);

// Out: 10 9 8 7 6 5 4 3 2 1 0

地点:

IntStream。迭代(int seed, IntPredicate hasNext, IntUnaryOperator next);

种子——初始元素; hasNext -应用于元素的谓词,以确定何时 流必须终止; Next -应用于前一个元素的函数,以生成一个 新元素。