相关疑难解决方法(0)

从流中收集连续的对

鉴于如下的流{ 0, 1, 2, 3, 4 },

我怎样才能最优雅地将其转换为给定的形式:

{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }

(假设,当然,我已经定义了类对)?

编辑:这不是严格关于整数或原始流.对于任何类型的流,答案应该是通用的.

java java-8 java-stream

92
推荐指数
10
解决办法
5万
查看次数

为什么共享可变性不好?

我正在观看关于Java的演讲,有一次,讲师说:

"可变性是可以的,分享是好的,共享的可变性是魔鬼的工作."

他所指的是以下一段代码,他认为这是一种"极其糟糕的习惯":

//double the even values and put that into a list.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4, 5);
List<Integer> doubleOfEven = new ArrayList<>();

numbers.stream()
       .filter(e -> e % 2 == 0)
       .map(e -> e * 2)
       .forEach(e -> doubleOfEven.add(e));
Run Code Online (Sandbox Code Playgroud)

然后他继续编写应该使用的代码,即:

List<Integer> doubleOfEven2 =
      numbers.stream()
             .filter(e -> e % 2 == 0)
             .map(e -> e * 2)
             .collect(toList());
Run Code Online (Sandbox Code Playgroud)

我不明白为什么第一段代码是"坏习惯".对我而言,他们都达到了同样的目标.

java immutability java-8 java-stream

46
推荐指数
3
解决办法
4580
查看次数

Java 8 findFirst并遇到订单

对JavaDoc中findFirst说,如果流有一个邂逅的命令,那么第一个元素总是会返回,但如果流没有遭遇订单,可以返回的任何元素.

我试图演示它如何在没有遭遇顺序的流上工作,但我不能让它返回除了实际的第一个元素之外的任何东西.

我尝试将元素添加到a Set,它没有定义的遭遇顺序:

    Set<String> words = new HashSet<>();
    words.addAll(Arrays.asList("this", "is", "a", "stream", "of", "strings"));
    Optional<String> firstString = words.stream()
            .findFirst();
    System.out.println(firstString);
Run Code Online (Sandbox Code Playgroud)

每次我跑,我得到a第一个字符串.然后我试图做一个Collections.shuffle关于List它添加到之前Set,但这并没有改变任何东西.

    List<String> wordList = Arrays.asList("this", "is", "a", "stream", "of", "strings");
    words = new HashSet<>();
    words.addAll(wordList);
    firstString = words.stream()
            .findFirst();
    System.out.println(firstString);
Run Code Online (Sandbox Code Playgroud)

a每次都会回复这个词.

然后我尝试使用unorderedfrom方法BaseStream,声称返回没有遇到顺序的流,但没有区别:

    firstString = Stream.of("this", "is", "a", "stream", "of", "strings")
            .unordered()
            .findFirst();
    System.out.println(firstString);
Run Code Online (Sandbox Code Playgroud)

现在我this每次都得到这个词.我错过了什么吗?有没有办法证明findFirst在无序流上返回不同的值?

java java-8

22
推荐指数
3
解决办法
3267
查看次数

Stream.max()如何处理相等?

虽然我怀疑答案是"它未指定"......

如果有多个"最大/最低"的元素Stream,其中Comparator传递到最大最小的方法认为等于(返回0)时,它指定某处哪个元素会被发现?

java java-8 java-stream

16
推荐指数
2
解决办法
704
查看次数

哪些操作保留了订单

TL; DR; 我正在寻找一个可以查找某个中间操作或终端操作的地方.我在哪里可以找到这样的文件?

编辑这与如何确保java8流中的处理顺序不重复,因为该问题没有提供全面的操作清单.

背景

软件包的文件说:

流是否具有遭遇顺序取决于源和中间操作

这个优秀的stackoverflow答案中重复了这一点

为了确保整个流操作中的订购维护,您必须研究流的源,所有中间操作和终端操作的文档,以确定它们是否维护订单(或者源是否在第一个订单中有订单)地点).

这一切都很好,但我应该查看哪些文档?该软件包文件提到了这样的例子map,保证订货,但它没有一个详尽的清单.Stream类javadoc记录了一些中间操作,但不是全部.举个例子map:

返回一个流,该流包含将给定函数应用于此流的元素的结果.

这是一个中间操作.

要么 filter

返回由与此给定谓词匹配的此流的元素组成的流.

这是一个中间操作.

这些都没有描述它们是否保留了排序.

此stackoverflow回答声称:

实际上,每个中间操作都默认保留订单.唯一的例外是:

  • unordered(),它删除了排序约束.
  • sorted()改变了顺序.

如果没有明确指定,您可以假设操作保持订单.即使distinct()保持顺序,但它为并行流增加了很多复杂性.

但是有任何官方文件可以支持吗?

额外的功劳

实际上有两个单独的排序问题.

  1. 操作的输出是否与输入保持相同的顺序?
  2. 是否按顺序对每个元素执行操作.

例如,并行map操作可以以任意顺序遍历所有元素(违反2.),但仍然保持返回流中的顺序(服从1.)

java java-8 java-stream

16
推荐指数
1
解决办法
6854
查看次数

并行无限 Java 流耗尽内存

我试图理解为什么下面的 Java 程序给出了OutOfMemoryError,而没有的相应程序没有.parallel()

System.out.println(Stream
    .iterate(1, i -> i+1)
    .parallel()
    .flatMap(n -> Stream.iterate(n, i -> i+n))
    .mapToInt(Integer::intValue)
    .limit(100_000_000)
    .sum()
);
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

  1. 这个程序的预期输出是什么?

    没有.parallel()它似乎只是输出sum(1+2+3+...),这意味着它只是“卡在” flatMap 中的第一个流,这是有道理的。

    使用并行我不知道是否有预期的行为,但我的猜测是它以某种方式交错了第一个n左右的流,n并行工作人员的数量在哪里。根据分块/缓冲行为,它也可能略有不同。

  2. 是什么导致它耗尽内存?我特别想了解这些流是如何在幕后实现的。

    我猜有什么东西阻塞了流,所以它永远不会完成并且能够摆脱生成的值,但我不太清楚事物的评估顺序以及缓冲发生的位置。

编辑:如果相关,我使用的是 Java 11。

编辑 2:显然即使对于简单的程序也会发生同样的事情IntStream.iterate(1,i->i+1).limit(1000_000_000).parallel().sum(),所以它可能与limit而不是的懒惰有关flatMap

java out-of-memory lazy-evaluation java-stream

16
推荐指数
2
解决办法
1484
查看次数

在Java 8中,顺序和有序流保证按顺序执行操作吗?

是否有一个操作的任何保证连续有序流的处理,遭遇订单

我的意思是,如果我有这样的代码:

IntStream.range(0, 5)
        .map(i -> {
            myFunction(i);
            return i * 2;
         })
         .boxed()
         .collect(toList());
Run Code Online (Sandbox Code Playgroud)

是否有保证,它将以生成范围的遭遇顺序执行myFunction()调用?

我找到了Stream类的JavaDocs草案,明确说明了这一点:

对于顺序流管道,如果管道源具有已定义的遭遇顺序,则所有操作都以管道源的遭遇顺序执行.

但在官方JavaDocs中,这一行被删除了.它现在仅讨论所选方法的遭遇顺序.该包装java.util.stream文档副作用款规定:

即使管道被约束以产生与流源的遭遇顺序一致的结果(例如,IntStream.range(0,5).parallel().map(x -> x*2).toArray()必须产生[0, 2, 4, 6, 8]),也不保证将映射器函数应用于各个元素的顺序,或者什么线程为给定元素执行任何行为参数.

但它没有说明顺序流,而且这个例子是针对并行流的(我的理解是顺序流和并行流都是如此,但这是我不确定的部分).

另一方面,它也在订购部分说明:

如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作; 如果流的源是List包含的[1, 2, 3],那么执行的结果map(x -> x*2)必须是[2, 4, 6].但是,如果源没有定义的遭遇顺序,则值的任何排列[2, 4, 6]都将是有效结果.

但这一次它以"对元素进行操作"开始,但是示例是关于产生的流,所以我不确定它们是否会考虑副作用,副作用实际上就是这个问题.

java java-stream

11
推荐指数
1
解决办法
1088
查看次数

流操作应用于列表元素的顺序是什么?

假设我们有一个标准的流操作方法链:

Arrays.asList("a", "bc", "def").stream()
  .filter(e -> e.length() != 2)
  .map(e -> e.length())
  .forEach(e -> System.out.println(e));
Run Code Online (Sandbox Code Playgroud)

JLS中是否有关于流操作应用于列表元素的顺序的保证?

例如,是否保证:

  1. 在应用过滤谓词"bc"之前,不会发生应用过滤谓词"a"
  2. 在应用映射函数"def"之前,应用映射函数是不会发生的"a"
  3. 1将在之前打印3

注意:我在这里专门讨论stream(),而不是 parallelStream()预期映射和过滤等操作并行完成的地方.

java java-8 java-stream

10
推荐指数
1
解决办法
1846
查看次数

遇到订单友好/不友好的终端操作与并行/顺序与有序/无序流

这个问题的启发,我开始玩有序与无序流,并行与顺序流和终端操作,这些操作尊重遭遇顺序与不尊重它的终端操作.

在对链接问题的一个答案中,显示了与此类似的代码:

List<Integer> ordered = Arrays.asList(
    1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 4);
List<Integer> result = new CopyOnWriteArrayList<>();

ordered.parallelStream().forEach(result::add);

System.out.println(ordered);
System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

这些名单确实不同.该unordered列表甚至从一次运行变为另一次运行,表明结果实际上是非确定性的.

所以我创建了另一个例子:

CopyOnWriteArrayList<Integer> result2 = ordered.parallelStream()
        .unordered()
        .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

System.out.println(ordered);
System.out.println(result2);
Run Code Online (Sandbox Code Playgroud)

我希望看到类似的结果,因为流是并行和无序的(可能unordered()是多余的,因为它已经是并行的).但是,生成的列表是有序的,即它等于源列表.

所以我的问题是为什么收集的清单是有序的?是否collect总是尊重遭遇顺序,即使对于并行,无序的流?它Collectors.toCollection(...)是强制遭遇秩序的特定收集者吗?

java java-8 java-stream

8
推荐指数
1
解决办法
128
查看次数

了解从HashSet生成的流中元素的顺序

我读了这篇Java 8官方文档:

流可能有也可能没有已定义的遭遇顺序.流是否具有遭遇顺序取决于源和中间操作.某些流源(例如List或数组)本质上是有序的,而其他流(例如HashSet)则不是.
如果订购了流,则在相同的源上重复执行相同的流管道将产生相同的结果; 如果没有订购,重复执行可能会产生不同的结果.

试图通过此代码了解上述行为

public class StreamOrderValidator
{
    public static void main( String[] args )
    {
        String[] colors=new String[] {"red","green","blue","orange"};
        List<String> colorsList=Arrays.asList(colors);

        HashSet<String> colorsSet=new HashSet<>();
        colorsSet.addAll(colorsList);
        System.out.println(colorsSet);            // [red, orange, green, blue]

        List<String> processedColorsSet = processStream(colorsSet.stream());
        System.out.println(processedColorsSet);   // [RED, ORANGE, GREEN, BLUE]
    }

    private static List<String> processStream(Stream<String> colorStream) {
        List<String> processedColorsList = colorStream.filter(s->s.length()<=6).
                map(String::toUpperCase).collect(Collectors.toList());
        return processedColorsList;
    }
}
Run Code Online (Sandbox Code Playgroud)

我多次运行此代码,结果流中元素的顺序始终相同(显示为注释).我无法弄清楚这是如何证明以上引用的文字"订单不被保留为无序集合".

我肯定误解了javadocs提取的文本.

java hashset java-8 java-stream

7
推荐指数
1
解决办法
331
查看次数