我如何用java8 streaming-API表达这个?
我想为流的每个项目执行
var casper = require('casper').create(); var fs = require('fs'); var data = fs.read('abc.txt'); casper.start(); casper.wait(5000, function () { console.log('wait 5000 for editing the file'); }); casper.then(function (){ console.log(data); }); casper.run();
。如果有 不是我想要执行的项目itemConsumer
。
当然我可以这样写:
emptyAction
但我宁愿避免任何Consumer<Object> itemConsumer = System.out::println;
Runnable emptyAction = () -> {System.out.println("no elements");};
Stream<Object> stream = Stream.of("a","b"); // or Stream.empty()
List<Object> list = stream.collect(Collectors.toList());
if (list.isEmpty())
emptyAction.run();
else
list.stream().forEach(itemConsumer);
。
我还想过在List
方法中设置一个标志 - 但该标志是非final的,因此不允许。使用布尔容器似乎也是一种解决方法。
答案 0 :(得分:3)
您可以强迫reduce
执行此操作。如果遇到任何有用的数据,逻辑将是减少false
,将值设置为true
。
reduce
的结果是false
,然后没有遇到任何项目。如果遇到任何项目,则结果为true
:
boolean hasItems = stream.reduce(false, (o, i) -> {
itemConsumer.accept(i);
return true;
}, (l, r) -> l | r);
if (!hasItems) {
emptyAction.run();
}
这应该适用于并行流,因为遇到项目的任何流都会将值设置为true
。
但是,我不确定我喜欢这个,因为它对reduce
操作的使用有点迟钝。
另一种方法是使用AtomicBoolean
作为可变boolean
容器:
final AtomicBoolean hasItems = new AtomicBoolean(false);
stream.forEach(i -> {
itemConsumer.accept(i);
hasItems.set(true);
});
if (!hasItems.get()) {
emptyAction.run();
}
但我不知道我是否更喜欢那样。
最后,您可以让itemConsumer
记住状态:
class ItemConsumer implements Consumer<Object> {
private volatile boolean hasConsumedAny;
@Override
public void accept(Object o) {
hasConsumedAny = true;
//magic magic
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer itemConsumer = new ItemConsumer();
stream.forEach(itemConsumer::accept);
if (!itemConsumer.isHasConsumedAny()) {
emptyAction.run();
}
这似乎有点整洁,但可能不实用。所以也许是一个装饰模式 -
class ItemConsumer<T> implements Consumer<T> {
private volatile boolean hasConsumedAny;
private final Consumer<T> delegate;
ItemConsumer(final Consumer<T> delegate) {
this.delegate = delegate;
}
@Override
public void accept(T t) {
hasConsumedAny = true;
delegate.accept(t);
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer<Object> consumer = new ItemConsumer<Object>(() -> /** magic **/);
TL; DR:某事必须记住在消费Stream
期间是否遇到过任何问题,不管是:
Stream
; 的情况下,reduce
本身
AtomicBoolean
;或从逻辑的角度来看,我认为消费者可能是最好的选择。
答案 1 :(得分:2)
没有任何其他变量的解决方案:
stream.peek(itemConsumer).reduce((a, b) -> a).orElseGet(() -> {
emptyAction.run();
return null;
});
请注意,如果流是并行的,则可以同时为不同线程中的不同元素调用itemConsumer
(例如forEach
,而不是forEachOrdered
)。如果第一个流元素为空,此解决方案也将失败。
答案 2 :(得分:1)
有一个简单的直接解决方案:
Spliterator<Object> sp=stream.spliterator();
if(!sp.tryAdvance(itemConsumer))
emptyAction.run();
else
sp.forEachRemaining(itemConsumer);
如果您愿意,您甚至可以在第一个之后保持对元素的并行支持:
Spliterator<Object> sp=stream.parallel().spliterator();
if(!sp.tryAdvance(itemConsumer))
emptyAction.run();
else
StreamSupport.stream(sp, true).forEach(itemConsumer);
在我看来,基于reduce
的解决方案更容易理解。
答案 3 :(得分:1)
你可以这样做:
if(stream.peek(itemConsumer).count() == 0){
emptyAction.run();
}
但是如果count
知道Java 9中peek
的大小(参见here),Stream
可能会被更改为跳过if(stream.peek(itemConsumer).mapToLong(e -> 1).sum() == 0){
emptyAction.run();
}
,所以如果你希望它能够在将来使用:
<div class="companies">
<ul class="logos">
<li><img src="images/image1.png" alt="" height="25px" /></li>
<li><img src="images/image2.png" alt="" height="25px" /></li>
<li><img src="images/image3.png" alt="" height="25px" /></li>
<li><img src="images/image4.png" alt="" height="25px" /></li>
<li><img src="images/image5.png" alt="" height="25px" /></li>
</ul>
</div>
/* Logos */
.companies {
width:100%;
}
ul.logos {
list-style:none;
margin:0 auto;
}
ul.logos li {
display: inline-block;
padding: 0 1em 0 0;
vertical-align: middle;
}
答案 4 :(得分:0)
使用reduce的另一种尝试:
Stream<Object> stream = Stream.of("a","b","c");
//Stream<Object> stream = Stream.empty();
Runnable defaultRunnable = () -> System.out.println("empty Stream");
Consumer<Object> printConsumer = System.out::println;
Runnable runnable = stream.map(x -> toRunnable(x, printConsumer)).reduce((a, b) -> () -> {
a.run();
b.run();
}).orElse(defaultRunnable);
runnable.run(); // prints a, b, c (or empty stream when it is empty)
// for type inference
static <T> Runnable toRunnable(T t, Consumer<T> cons){
return ()->cons.accept(t);
}
此方法不使用peek()
Dim i As Long
For i = LBound(SampleArray) To UBound(SampleArray)
ListBox1.AddItem SampleArray(i)
Next