Java 在列表中查找元素并使用stream()对其进行更改
是否可以使用Java 8流在Java 在列表中查找元素并使用stream()对其进行更改,java,java-8,java-stream,Java,Java 8,Java Stream,是否可以使用Java 8流在列表中找到元素、更改它或在未找到元素时抛出异常 换句话说,我想使用stream重写以下代码。我能得到的最好结果是更改项目值,但无法确定是否找到/更改了项目 boolean isFound = false; for (MyItem item : myList) { if (item.getValue() > 10) { item.setAnotherValue(5); isFound = true; } } if
列表
中找到元素、更改它或在未找到元素时抛出异常
换句话说,我想使用stream
重写以下代码。我能得到的最好结果是更改项目值,但无法确定是否找到/更改了项目
boolean isFound = false;
for (MyItem item : myList) {
if (item.getValue() > 10) {
item.setAnotherValue(5);
isFound = true;
}
}
if (!isFound) {
throw new ElementNotFoundException("Element 10 wasn't found");
}
如果你的目标是只找到一个元素,你可以这样做
MyItem item = l.stream()
.filter(x -> x.getValue() > 10)
.findAny() // here we get an Optional
.orElseThrow(() -> new RuntimeException("Element 10 wasn't found"));
item.setAnotherValue(4);
在Java 9中,使用ifpresentorese
,这可以稍微简化为(不幸的是,语法()->{throw new RuntimeException();}
也有点笨拙,但恐怕无法简化):
如果您想对所有项目都这样做,您可以尝试类似的方法。但是,由于Java 8流不是设计为通过副作用运行的,因此这不是一种真正干净的方法:
AtomicBoolean b = new AtomicBoolean(false);
l.stream()
.filter(x -> x.getValue() > 10)
.forEach(x->{
x.setAnotherValue(5);
b.set(true);
});
if (b.get()){
throw new RuntimeException();
}
当然,您也可以简单地将元素收集到一个列表中,然后执行操作。但我不确定这是否比您开始使用的简单for循环有任何改进
如果
forEach
返回一个long
,它表示调用它的元素的数量,这将更容易…原子布尔解决方案看起来很糟糕。它更像是收集的任务:booleanHadMatches=l.stream().filter(x->x.getValue()>10)。收集(()->新的布尔值[1],(b,x)->{x.setAnotherValue(5);b[0]=true;},(b1,b2)->b1[0]|=b2[0])[0]代码>@Holger:我想这两种解决方案都不是特别优雅的。或者,您认为在并行流中使用该原子布尔
时可能存在争用问题吗?在这种情况下,这不是争用(因为所有消费者都只编写而不是执行cas
),而是在每个元素的处理之间存在内存障碍,阻碍了热点优化,这甚至在顺序执行中也是如此,除非优化器发现这个AtomicBoolean
纯粹是本地的。collect
操作看起来可能不太优雅,但与映射(x->{x.setAnotherValue(5);return true;},reduce(false,Boolean::logicalOr))非常接近。哦,等等,这可能是另一种选择……好的,那么我们也可以使用.map(x->{x.setAnotherValue(5);返回true;})代码>。在这两种情况下,副作用轴承的作用必须放在某处…
AtomicBoolean b = new AtomicBoolean(false);
l.stream()
.filter(x -> x.getValue() > 10)
.forEach(x->{
x.setAnotherValue(5);
b.set(true);
});
if (b.get()){
throw new RuntimeException();
}