我试图找出如何在Java8 Stream上实现自定义中间操作。似乎我被锁在外面了:(
具体地说,我想获取一个流,并返回每个条目,包括第一个具有特定值的条目。我想在那之后停止发电,让它短路。
它正在对输入数据进行一系列验证检查。如果有第一个错误,我想停止,但我想在途中整理警告。而且因为这些验证检查可能很昂贵——例如,涉及数据库查找——我只想运行所需的最小集。
所以代码应该是这样的:
Optional<ValidationResult> result = validators.stream()
.map(validator -> validator.validate(data))
.takeUntil(result -> result.isError()) // This is the bit I can't do
.reduce(new ValidationResult(), ::mergeResults);
看来我应该可以用ReferencePipeline做点什么。StatefulOp,除了它是所有包的作用域,所以我不能扩展它。所以我想知道实现这一目标的正确方法是什么?或者如果可能的话?
还要注意——这需要在Java8中实现,而不是在9中,因为我们由于各种不相关的原因还没有实现。
干杯
你可以用一个技巧来做到:
List<ValidationResult> res = new ArrayList<>(); // Can modify it with your `mergeResults` instead of list
Optional<ValidationResult> result = validators.stream()
.map(validator -> validator.validate(data))
.map(v -> {
res.add(v);
return v;
})
.filter(result -> result.isError())
.findFirst();
列表
我承认在代码方面,霍尔格的答案要性感得多,但也许这更容易阅读:
public static <T> Stream<T> takeUntilIncluding(Stream<T> s, Predicate<? super T> condition) {
class Box implements Consumer<T> {
boolean stop = false;
T t;
@Override
public void accept(T t) {
this.t = t;
}
}
Box box = new Box();
Spliterator<T> original = s.spliterator();
return StreamSupport.stream(new AbstractSpliterator<>(
original.estimateSize(),
original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) {
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (!box.stop && original.tryAdvance(box) && condition.test(box.t)) {
action.accept(box.t);
return true;
}
box.stop = true;
return false;
}
}, s.isParallel());
}
通常,自定义操作需要处理Spliterator
接口。它扩展了Iterator
的概念,添加了特性和大小信息,并能够将一部分元素拆分为另一个拆分器(因此得名)。它还简化了迭代逻辑,只需要一种方法。
public static <T> Stream<T> takeWhile(Stream<T> s, Predicate<? super T> condition) {
boolean parallel = s.isParallel();
Spliterator<T> spliterator = s.spliterator();
return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
spliterator.estimateSize(),
spliterator.characteristics()&~(Spliterator.SIZED|Spliterator.SUBSIZED)) {
boolean active = true;
Consumer<? super T> current;
Consumer<T> adapter = t -> {
if((active = condition.test(t))) current.accept(t);
};
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if(!active) return false;
current = action;
try {
return spliterator.tryAdvance(adapter) && active;
}
finally {
current = null;
}
}
}, parallel).onClose(s::close);
}
为了保留流的属性,我们首先查询并行状态,以便为新流重新建立它。此外,我们注册一个关闭操作,将关闭原始流。
主要工作是实现一个拆分器
装饰先前流状态的拆分器。
除了大小的
和补贴的
之外,这些特征都被保留下来,因为我们的操作会导致不可预测的大小。原始尺寸仍在传递中,现在将用作估计值。
此解决方案在操作期间存储传递给tryAdvance
的Consumer
,以便能够使用相同的适配器Consumer,避免为每次迭代创建新的适配器Consumer。这是可行的,因为可以保证tryAdvance
永远不会被并发调用。
并行性是通过拆分实现的,拆分是从AbstractSpliterator
继承的。这种继承的实现将缓冲一些元素,这是合理的,因为为像takeWhile
这样的操作实现更好的策略非常复杂。
所以你可以像这样使用它
takeWhile(Stream.of("foo", "bar", "baz", "hello", "world"), s -> s.length() == 3)
.forEach(System.out::println);
哪个会打印
foo
bar
baz
或
takeWhile(Stream.of("foo", "bar", "baz", "hello", "world")
.peek(s -> System.out.println("before takeWhile: "+s)), s -> s.length() == 3)
.peek(s -> System.out.println("after takeWhile: "+s))
.forEach(System.out::println);
哪个会打印
before takeWhile: foo
after takeWhile: foo
foo
before takeWhile: bar
after takeWhile: bar
bar
before takeWhile: baz
after takeWhile: baz
baz
before takeWhile: hello
这表明它不会处理超出需要的内容。在takeWhile
阶段之前,我们必须遇到第一个不匹配的元素,在那之后,我们只会遇到之前的元素。
问题内容: 我要实现ActionBar必须如下所示的自定义: 所以问题: 如何实现类似自定义视图的按钮:仅显示一些图像? 如何在顶部绘制一条线? 以及如何实现不带分隔线的按钮:在上添加标签或添加什么? 问题答案: 如果要使用ActionBarAPI,这几乎与你将获得的接近。我不确定你是否可以在ActionBar不进行奇怪的Window黑客操作的情况下在其上方放置一个色带,这是不值得的。至于更改Me
我想实现定制的,它必须如下所示: 所以问题是: 如何实现自定义视图这样的按钮:只是一些图像
是否可以为Java8并行流指定自定义线程池?我到处都找不到它。 如果我不能为不同的模块使用不同的线程池,这就意味着我不能在大多数真实世界的情况下安全地使用并行流。 请尝试以下示例。有些CPU密集型任务在单独的线程中执行。这些任务利用并行流。第一个任务被打破,因此每一步需要1秒(通过线程Hibernate模拟)。问题是其他线程会被卡住,等待中断的任务完成。这是一个虚构的示例,但假设一个servlet
问题内容: 我解析了.yaml文件,需要以自定义方式解组其属性之一。我正在使用包裹。 有问题的属性按如下方式存储在我的.yaml文件中: 因此,它基本上是一种类型。 但是我需要在哪里定义为: 我的结构: 我试图像这样实现Unmarshaler接口: 我的问题是在函数内部未定义类型,从而在运行时导致nil指针异常。 我如何在此处正确实现Unmarshaler接口? 问题答案: 由于@Volker并未
本文向大家介绍IOS实现自定义布局瀑布流,包括了IOS实现自定义布局瀑布流的使用技巧和注意事项,需要的朋友参考一下 瀑布流是电商应用展示商品通常采用的一种方式,如图示例 瀑布流的实现方式,通常有以下几种 通过UITableView实现(不常用) 通过UIScrollView实现(工作量较大) 通过UICollectionView实现(通常采用的方式) 一、UICollectionView基础 1、
本文向大家介绍Android自定义ViewGroup实现流式布局,包括了Android自定义ViewGroup实现流式布局的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android自定义ViewGroup实现流式布局的具体代码,供大家参考,具体内容如下 1.概述 本篇给大家带来一个实例,FlowLayout,什么是FlowLayout,我们常在App 的搜索界面看到热门搜索词,就