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

具体问题:

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)

我错过了什么?


当前回答

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

其他回答

如何避免这样做:

不要使用.sorted(Comparator.reverseOrder())或.sorted(Collections.reverseOrder()),因为它只会按降序排序元素。 对于给定的Integer输入使用它: [1,4,2,5,3] 输出结果如下: [5,4,3,2,1] 对于字符串输入: [" a ", " d ", " b ", " e ", " c "] 输出结果如下: [e, d, c, b, a] 不要使用.sorted((a, b) -> -1)(后面的解释)

最简单的正确方法是:

List<Integer> list = Arrays.asList(1, 4, 2, 5, 3);
Collections.reverse(list);
System.out.println(list);

输出: [3,5,2,4,1]

String也一样:

List<String> stringList = Arrays.asList("A", "D", "B", "E", "C");
Collections.reverse(stringList);
System.out.println(stringList);

输出: [c, e, b, d, a]

不要使用.sorted((a, b) -> -1)! 它打破了比较国契约,可能只适用于某些情况。只在单线程上,而不是并行。 洋基的解释:

(a, b) -> -1打破了Comparator的契约。这是否有效取决于排序算法的实现。JVM的下一个版本可能会打破这一点。实际上,我已经可以在我的机器上使用IntStream重复地打破这个。.boxed范围(0 10000).parallel()()。sorted((a, b) -> -1).forEachOrdered(System.out::println);

//Don't use this!!!
List<Integer> list = Arrays.asList(1, 4, 2, 5, 3);
List<Integer> reversedList = list.stream()
        .sorted((a, b) -> -1)
        .collect(Collectors.toList());
System.out.println(reversedList);

正数输出: [3,5,2,4,1]

可能的输出在并行流或与其他JVM实现: [4,1,2,3,5]

String也一样:

//Don't use this!!!
List<String> stringList = Arrays.asList("A", "D", "B", "E", "C");
List<String> reversedStringList = stringList.stream()
        .sorted((a, b) -> -1)
        .collect(Collectors.toList());
System.out.println(reversedStringList);

正数输出: [c, e, b, d, a]

可能的输出在并行流或与其他JVM实现: [a, e, b, d, c]

回答与IntStream反转的具体问题,以下工作对我来说:

IntStream.range(0, 10)
  .map(x -> x * -1)
  .sorted()
  .map(Math::abs)
  .forEach(System.out::println);

在所有这些问题中,我没有看到我首先要回答的答案。

这并不是对这个问题的直接回答,但却是一个潜在的解决方案。

只要一开始就逆向构建列表。如果可以的话,使用LinkedList而不是ArrayList,当你添加项目时使用“Push”而不是add。列表将以相反的顺序构建,然后将正确地流,而不需要任何操作。

这并不适用于您正在处理原始数组或列表的情况,这些原始数组或列表已经以各种方式使用,但在令人惊讶的大量情况下工作得很好。

ArrayDeque在堆栈中比stack或LinkedList更快。"push()"将元素插入到Deque的前面

 protected <T> Stream<T> reverse(Stream<T> stream) {
    ArrayDeque<T> stack = new ArrayDeque<>();
    stream.forEach(stack::push);
    return stack.stream();
}

最简单的解决方案是使用List::listIterator和Stream::generate

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
ListIterator<Integer> listIterator = list.listIterator(list.size());

Stream.generate(listIterator::previous)
      .limit(list.size())
      .forEach(System.out::println);