流管道可以顺序执行或并行执行.此执行模式是流的属性.通过初始选择的顺序或并行执行来创建流.
我的假设:
假设这些假设是有效的(对于一些元假设没有错误),在api中暴露执行模式的价值是什么?
看起来您应该只能声明一个Stream,并且顺序/并行执行的选择应该在下面的层中自动处理,可以通过库代码或JVM本身作为运行时可用核心的函数来处理,大小问题等
当然,假设并行流也可以在单个核心机器上运行,也许只是总是使用并行流来实现这一点.但这真的很难看 - 为什么我的代码中的并行流显式引用它是默认选项?
即使存在您故意想要对顺序流进行硬编码的情况 - 为什么不仅仅是SequentialStream为此目的的子接口,而不是Stream使用执行模式切换进行污染?
是否有一种理智的方式从列表中获取有序流(具体来说,数组列表,但它应该无关紧要)流式元素与它们在原始列表中的方式相反?
我正在寻找一种不涉及缓冲数据的解决方案(收集器,另一个列表,数组等,因为它们复制了浪费的容器),或者使用Collections.reverse(因为它修改了列表).
到目前为止,我在这里看到的最干净的方法之一是实现我自己的版本的Spliterator这ORDERED和在列表中反向前进,或实施Iterator反向迭代是,并使用Spliterators.spliteratorUnknownSize(iterator,ORDERED)它.
注意这个问题不同于Java 8流逆序:其他问题询问如何反转流(一般情况下这是不可能的),并且答案提供了以某种方式反转源(我不想这样做),然后传输反向源.逆转源的成本是O(N),如果可能的话我想完全避免它.
我想排序seq1升序和seq2降序所以我这样做:
list = list.stream().sorted(comparing(AClass::getSeq1).thenComparing(
AClass::getSeq2).reversed()).collect(toList());
Run Code Online (Sandbox Code Playgroud)
但结果出来了,因为seq1和seq2都按降序排序.
我可以这样做以使seq1升序和seq2降序:
sorted(comparing(AClass::getSeq1)
.reversed().thenComparing(AClass::getSeq2).reversed()
Run Code Online (Sandbox Code Playgroud)
这是真正的正确方法吗?
我试图了解是否有办法终止还原操作而不检查整个流,我无法找到方法.
用例大致如下:让一长串的Integers需要折叠成一个Accumulator.每个元素检查都可能很昂贵,所以在内部Accumulator,我对传入进行检查Accumulator,看看我们是否需要执行昂贵的操作 - 如果我们不这样做,那么我只需返回累加器.
对于小(呃)列表来说,这显然是一个很好的解决方案,但是巨大的列表会产生我不想要的不必要的流元素访问成本.
这是一个代码草图 - 仅假设连续减少.
class Accumulator {
private final Set<A> setA = new HashSet<>;
private final Set<B> setB = new HashSet<>;
}
class ResultSupplier implements Supplier<Result> {
private final List<Integer> ids;
@Override
public Result get() {
Accumulator acc = ids.stream().reduce(new Accumulator(), f(), (x, y) -> null);
return (acc.setA.size > 1) ? Result.invalid() : Result.valid(acc.setB);
}
private static BiFunction<Accumulator, Integer, Accumulator> f() {
return (acc, element) -> {
if …Run Code Online (Sandbox Code Playgroud) 我试图弄清楚如何总结'ArrayList'的所有元素.
我已经尝试过了:
double totalevent = myList.stream().mapToDouble(f -> f).sum();
Run Code Online (Sandbox Code Playgroud)
虽然myList是一个ArrayList<Double>.
没有无用的mapToDouble功能有没有办法做到这一点?
假设我们有一个由唯一Strings 标识的对象集合,以及一个Tree定义它们层次结构的类.该类使用Mapfrom节点(由其ID表示)到Collection其各自子节点的s来实现.
class Tree {
private Map<String, Collection<String>> edges;
// ...
public Stream<String> descendants(String node) {
// To be defined.
}
}
Run Code Online (Sandbox Code Playgroud)
我想启用流式节点的后代.一个简单的解决方案是:
private Stream<String> children(String node) {
return edges.getOrDefault(node, Collections.emptyList()).stream();
}
public Stream<String> descendants(String node) {
return Stream.concat(
Stream.of(node),
children(node).flatMap(this::descendants)
);
}
Run Code Online (Sandbox Code Playgroud)
在继续之前,我想对此解决方案做出以下断言.(我对这些是正确的吗?)
从Stream返回的descendants消耗资源(时间和内存) - 相对于树的大小 - 以与手动编码递归相同的复杂度顺序行走.特别地,表示迭代状态(Streams,Spliterators,...)的中间对象形成堆栈,因此在任何给定时间的存储器要求与树的深度具有相同的复杂度.
据我所知此,只要我在执行终止操作Stream从返回descendants,根级别调用flatMap将导致所有包含Stream秒-一个用于每个(递归)呼叫descendants-被立即实现.因此,结果Stream …
我想把一个人的名单分组.一个人有一些属性,如姓名,国家,城镇,邮政编码等.我写了静态代码,非常有效:
Object groupedData = data.stream().collect(groupingBy(Person::getName, Collectors.groupingBy(Person::getCountry, Collectors.groupingBy(Person::getTown))));
Run Code Online (Sandbox Code Playgroud)
但问题是,这不是动态的.有时我想按名称和城镇分组,有时候按属性分组.我怎样才能做到这一点?非Java 8解决方案也是受欢迎的.
我想循环一个庞大的数组并做一组复杂的指令需要很长时间.但是,如果超过30秒,我希望它放弃.
恩.
final long start = System.currentTimeMillis();
myDataStructure.stream()
.while(() -> System.currentTimeMillis() <= start + 30000)
.forEach(e ->
{
...
});
Run Code Online (Sandbox Code Playgroud)
如果满足某个条件,我想避免return在forEach通话中说话.
我的理解是,Stream一旦执行终端操作(例如forEach()或)count(),就认为Java 8 被消耗.
但是,multipleFilters_separate下面的测试用例抛出一个IllegalStateException即使filter是一个懒惰的中间操作,只是作为两个语句调用.然而,我可以将两个过滤操作链接到一个语句中并且它可以工作.
@Test(expected=IllegalStateException.class)
public void multipleFilters_separate() {
Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
ints.filter(d -> d > 1.3);
ints.filter(d -> d > 2.3).forEach(System.out::println);
}
@Test
public void multipleFilters_piped() {
Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
ints.filter(d -> d > 1.3)
.filter(d -> d > 2.3)
.forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)
从这开始,我假设Stream在第一个使用它的语句之后被认为是消耗的,无论该语句是否调用终端操作.听起来不错吗?
基本上这是在试图回答另一个问题时出现的.假设这段代码:
AtomicInteger i = new AtomicInteger(0);
AtomicInteger count = new AtomicInteger(0);
IntStream.generate(() -> i.incrementAndGet())
.parallel()
.peek(x -> count.incrementAndGet())
.limit(5)
.forEach(System.out::println);
System.out.println("count = " + count);
Run Code Online (Sandbox Code Playgroud)
我理解这IntStream#generate是一个无序的无限流的事实,并且要完成它必须有一个短路操作(limit在这种情况下).我也明白,在Supplier达到该限制之前,Stream实现的次数可以自由调用.
在java-8下运行它会count一直打印512(可能并不总是,但在我的机器上是这样).
在对比运行中,这在java-10下很少超过5.所以我的问题是内部发生了什么变化,短路发生得更好(我试图通过拥有源并试图做一些差异来解决这个问题......)
java-8 ×10
java-stream ×10
java ×9
algorithm ×1
collectors ×1
comparator ×1
double ×1
fold ×1
grouping ×1
java-10 ×1
reduce ×1
sorting ×1