Java 在列表中查找元素并使用stream()对其进行更改

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

是否可以使用Java 8流在
列表
中找到元素、更改它或在未找到元素时抛出
异常

换句话说,我想使用
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();
}