鉴于如下的流{ 0, 1, 2, 3, 4 },
我怎样才能最优雅地将其转换为给定的形式:
{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }
(假设,当然,我已经定义了类对)?
编辑:这不是严格关于整数或原始流.对于任何类型的流,答案应该是通用的.
我正在观看关于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)
我不明白为什么第一段代码是"坏习惯".对我而言,他们都达到了同样的目标.
在对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在无序流上返回不同的值?
TL; DR; 我正在寻找一个可以查找某个中间操作或终端操作的地方.我在哪里可以找到这样的文件?
编辑这与如何确保java8流中的处理顺序不重复?,因为该问题没有提供全面的操作清单.
该软件包的文件说:
流是否具有遭遇顺序取决于源和中间操作
为了确保整个流操作中的订购维护,您必须研究流的源,所有中间操作和终端操作的文档,以确定它们是否维护订单(或者源是否在第一个订单中有订单)地点).
这一切都很好,但我应该查看哪些文档?该软件包文件提到了这样的例子map,保证订货,但它没有一个详尽的清单.Stream类的javadoc记录了一些中间操作,但不是全部.举个例子map:
返回一个流,该流包含将给定函数应用于此流的元素的结果.
这是一个中间操作.
要么 filter
返回由与此给定谓词匹配的此流的元素组成的流.
这是一个中间操作.
这些都没有描述它们是否保留了排序.
实际上,每个中间操作都默认保留订单.唯一的例外是:
- unordered(),它删除了排序约束.
- sorted()改变了顺序.
如果没有明确指定,您可以假设操作保持订单.即使distinct()保持顺序,但它为并行流增加了很多复杂性.
但是有任何官方文件可以支持吗?
实际上有两个单独的排序问题.
例如,并行map操作可以以任意顺序遍历所有元素(违反2.),但仍然保持返回流中的顺序(服从1.)
我试图理解为什么下面的 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)
我有两个问题:
这个程序的预期输出是什么?
没有.parallel()它似乎只是输出sum(1+2+3+...),这意味着它只是“卡在” flatMap 中的第一个流,这是有道理的。
使用并行我不知道是否有预期的行为,但我的猜测是它以某种方式交错了第一个n左右的流,n并行工作人员的数量在哪里。根据分块/缓冲行为,它也可能略有不同。
是什么导致它耗尽内存?我特别想了解这些流是如何在幕后实现的。
我猜有什么东西阻塞了流,所以它永远不会完成并且能够摆脱生成的值,但我不太清楚事物的评估顺序以及缓冲发生的位置。
编辑:如果相关,我使用的是 Java 11。
编辑 2:显然即使对于简单的程序也会发生同样的事情IntStream.iterate(1,i->i+1).limit(1000_000_000).parallel().sum(),所以它可能与limit而不是的懒惰有关flatMap。
是否有一个操作的任何保证连续和有序流的处理,在遭遇订单?
我的意思是,如果我有这样的代码:
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]都将是有效结果.
但这一次它以"对元素进行操作"开始,但是示例是关于产生的流,所以我不确定它们是否会考虑副作用,副作用实际上就是这个问题.
假设我们有一个标准的流操作方法链:
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中是否有关于流操作应用于列表元素的顺序的保证?
例如,是否保证:
"bc"之前,不会发生应用过滤谓词"a"?"def"之前,应用映射函数是不会发生的"a"?1将在之前打印3?注意:我在这里专门讨论stream(),而不是 parallelStream()预期映射和过滤等操作并行完成的地方.
受这个问题的启发,我开始玩有序与无序流,并行与顺序流和终端操作,这些操作尊重遭遇顺序与不尊重它的终端操作.
在对链接问题的一个答案中,显示了与此类似的代码:
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 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提取的文本.