在Java 8中,Collection接口扩展了两个返回的方法Stream<E>:stream()返回一个顺序流,并parallelStream()返回一个可能并行的流.流本身也有一个parallel()返回等效并行流的方法(将当前流变为并行或创建新流).
复制有明显的缺点:
这令人困惑.一个问题是,如果parallelStream()可能返回顺序流,是否需要同时调用parallelStream().parallel()以确保流是并行的.如果无法保证parallelStream(),为什么会存在?反过来也是混乱 - 如果parallelStream()返回顺序流,则可能有一个原因(例如,并行流是性能陷阱的固有顺序数据结构); Stream.parallel()应该为这样的流做什么?(parallel()的规范不允许使用UnsupportedOperationException.)
如果现有实现具有类似命名的方法且返回类型不兼容,则向接口添加方法会产生冲突.除了stream()之外,添加parallelStream()会使得收益微不足道的风险增加一倍.(注意,parallelStream()只是名为parallel(),但我不知道它是否被重命名以避免名称冲突或其他原因.)
为什么在调用Collection.stream()时才存在Collection.parallelStream().parallel()做同样的事情?
我想使用parallelStream并行化以下代码:
boolean anyTrue() {
for (Element e : setOfE) {
if (eval(e)) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
以下是否可以在并行流上使用并定期进行短路评估?
setOfE.parallelStream().map(e -> eval(e)).reduce(false, (a,b) -> a || b))
Run Code Online (Sandbox Code Playgroud) 我有一个List<Item>集合.我需要将其转换Map<Integer, Item>
为映射的键必须是集合中项的索引.我无法弄清楚如何使用流来做到这一点.就像是:
items.stream().collect(Collectors.toMap(...));
Run Code Online (Sandbox Code Playgroud)
有帮助吗?
由于这个问题被确定为可能重复,我需要补充一点,我的具体问题是 - 如何获取列表中项目的位置并将其作为键值
将String拆分为Stream 的最佳方法是什么?
我看到了这些变化:
Arrays.stream("b,l,a".split(","))Stream.of("b,l,a".split(","))Pattern.compile(",").splitAsStream("b,l,a")我的优先事项是:
一个完整的,可编译的例子:
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class HelloWorld {
public static void main(String[] args) {
stream1().forEach(System.out::println);
stream2().forEach(System.out::println);
stream3().forEach(System.out::println);
}
private static Stream<String> stream1() {
return Arrays.stream("b,l,a".split(","));
}
private static Stream<String> stream2() {
return Stream.of("b,l,a".split(","));
}
private static Stream<String> stream3() {
return Pattern.compile(",").splitAsStream("b,l,a");
}
}
Run Code Online (Sandbox Code Playgroud) 目前我们Stream.concat在Java 8中有以下内容:
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b);
Run Code Online (Sandbox Code Playgroud)
我很惊讶为什么没有版本采取varargs Stream<? extends T>?
目前我的代码编写如下:
Stream<Integer> resultStream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element)))
.filter(x -> x != 0)
.filter(x -> x != 1)
.filter(x -> x != 2);
Run Code Online (Sandbox Code Playgroud)
如果提供此签名的varargs:
public static <T> Stream<T> concat(Stream<? extends T>... streams);
Run Code Online (Sandbox Code Playgroud)
然后我可以更清楚地写出:
Stream<Integer> resultStream = Stream.concat(
stream1,
stream2,
Stream.of(element)
)
.filter(x -> x != 0)
.filter(x -> x != 1)
.filter(x -> x != 2);
Run Code Online (Sandbox Code Playgroud)
没有各种嵌套Stream.concat调用.
还是有其他原因没有提供? …
我有一个List<Foo>并且想要一个Multimap<String, Foo>我们Foo根据他们的getId()功能对其进行分组的地方.
我正在使用Java 8,它几乎可以做到:
List<Foo> foos = ...
Map<String, List<Foo>> foosById = foos.stream().collect(groupingBy(Foo::getId));
Run Code Online (Sandbox Code Playgroud)
但是,我有大量的代码需要一个,MultiMap<String, Foo>所以这并没有为我节省任何东西,我回到使用for循环来创建我的MultiMap.我错过了一个很好的"功能性"方式吗?
在Java8中运行以下流示例:
System.out.println(Stream
.of("a", "b", "c", "d", "e", "f")
.reduce("", (s1, s2) -> s1 + "/" + s2)
);
Run Code Online (Sandbox Code Playgroud)
收益率:
/a/b/c/d/e/f
Run Code Online (Sandbox Code Playgroud)
这是 - 当然 - 毫不奇怪.由于http://docs.oracle.com/javase/8/docs/api/index.html?overview-summary.html,流顺序执行还是并行执行无关紧要:
除了标识为显式非确定性的操作(例如findAny())之外,流是顺序执行还是并行执行不应更改计算结果.
AFAIK reduce()是确定性的并且(s1, s2) -> s1 + "/" + s2是关联的,因此添加parallel()应该产生相同的结果:
System.out.println(Stream
.of("a", "b", "c", "d", "e", "f")
.parallel()
.reduce("", (s1, s2) -> s1 + "/" + s2)
);
Run Code Online (Sandbox Code Playgroud)
但是我机器上的结果是:
/a//b//c//d//e//f
Run Code Online (Sandbox Code Playgroud)
这有什么不对?
BTW:使用(首选).collect(Collectors.joining("/"))而不是为顺序和并行执行reduce(...)产生相同的结果a/b/c/d/e/f.
JVM详细信息:
java.specification.version: 1.8
java.version: 1.8.0_31
java.vm.version: 25.31-b07
java.runtime.version: 1.8.0_31-b13
Run Code Online (Sandbox Code Playgroud) 我正在使用Java 8流来迭代包含子列表的列表.外部列表大小在100到1000之间(不同的测试运行),内部列表大小始终为5.
有2个基准测试运行显示意外的性能偏差.
package benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
@Threads(32)
@Warmup(iterations = 25)
@Measurement(iterations = 5)
@State(Scope.Benchmark)
@Fork(1)
@BenchmarkMode(Mode.Throughput)
public class StreamBenchmark {
@Param({"700", "600", "500", "400", "300", "200", "100"})
int outerListSizeParam;
final static int INNER_LIST_SIZE = 5;
List<List<Integer>> list;
Random rand() {
return ThreadLocalRandom.current();
}
final BinaryOperator<Integer> reducer = (val1, val2) -> val1 + val2;
final Supplier<List<Integer>> supplier = () -> IntStream
.range(0, INNER_LIST_SIZE)
.mapToObj(ptr -> rand().nextInt(100))
.collect(Collectors.toList());
@Setup …Run Code Online (Sandbox Code Playgroud) Stream的javadoc说明:
Streams有一个BaseStream.close()方法并实现AutoCloseable,但几乎所有的流实例实际上都不需要在使用后关闭.通常,只有源为IO通道的流(例如Files.lines(Path,Charset)返回的流)才需要关闭.大多数流都由集合,数组或生成函数支持,不需要特殊的资源管理.(如果流确实需要关闭,则可以在try-with-resources语句中将其声明为资源.)
因此,绝大多数情况下,人们可以在单行中使用Streams,collection.stream().forEach(System.out::println);但是对于Files.lines和其他资源支持的流,必须使用try-with-resources语句或泄漏资源.
这让我觉得容易出错并且不必要.因为Streams只能迭代一次,所以在我看来,没有一个迭代后Files.lines不应该关闭输出的情况,因此实现应该只是在任何终端操作结束时隐式调用close .我错了吗?
我有一个Map<String, Double>,并希望将地图中的所有值乘以2,比方说,但是将空值保持为空.
我显然可以使用for循环来做到这一点,但是想知道是否有更清洁的方法呢?
Map<String, Double> someMap = someMapFunction();
Map<String, Double> adjustedMap = new Hashmap<>();
if (someMap != null) {
for (Map.Entry<String,Double> pair : someMap.entryset()) {
if (pair.getValue() == null) {
adjustedMap.put(pair.getKey(), pair.getValue());
} else {
adjustedMap.put(pair.getKey(), pair.getValue()*2)
}
}
}
Run Code Online (Sandbox Code Playgroud)
有时候返回的地图someMapFunction是一个不可变的地图,所以这不能用就地做Map.replaceAll.我无法想出一个更清洁的流解决方案.
java-stream ×10
java ×9
java-8 ×8
lambda ×3
collections ×1
dictionary ×1
guava ×1
jmh ×1
performance ×1
regex ×1
split ×1
stream ×1