我有以下代码:
interface Device {
// ...
boolean isDisconnected();
void reconnect();
}
interface Gateway {
// ...
List<Device> getDevices();
}
...
for (Gateway gateway : gateways) {
for(Device device : gateway.getDevices()){
if(device.isDisconnected()){
device.reconnect();
}
}
}
我想使用Stream API重构代码。我的第一次尝试如下:
gateways
.stream()
.forEach(
gateway -> {
gateway
.getDevices()
.parallelStream()
.filter(device -> device.isDisconnected())
.forEach(device -> device.reconnect())
;
}
)
;
我不喜欢它,因此在进行了一些修改之后,我得到了以下代码:
gateways
.parallelStream()
.map(gateway -> gateway.getDevices().parallelStream())
.map(stream -> stream.filter(device -> device.isDisconnected()))
.forEach(stream -> stream.forEach(device -> device.reconnect()))
;
我的问题是是否有避免嵌套forEach
的方法。
答案 0 :(得分:16)
您应该使用flatMap
而不是map
来简化流的流:
gateways
.parallelStream()
.flatMap(gateway -> gateway.getDevices().parallelStream())
.filter(device -> device.isDisconnected())
.forEach(device -> device.reconnect());
我将通过使用方法引用而不是lambda表达式来进一步改进它:
gateways
.parallelStream()
.map(Gateway::getDevices)
.flatMap(List::stream)
.filter(Device::isDisconnected)
.forEach(Device::reconnect);
答案 1 :(得分:11)
不要将您的代码重构为使用Streams。这样做对您没有好处,也没有任何好处,因为该代码现在对于将来的维护者来说可读性越来越差,习惯性也越来越少。
通过不使用流,可以避免嵌套forEach
语句。
请记住:为了更安全的并行化,流应无副作用。 forEach
根据定义引入了副作用。您失去了流的好处,同时失去了可读性,因此根本就不希望这样做。
答案 2 :(得分:4)
在使用并行流之前,我会尝试使用顺序流:
gateways
.stream()
.flatMap(gateway -> gateway.getDevices().stream())
.filter(device -> device.isDisconnected())
.forEach(device -> device.reconnect())
;
想法是通过gateways.stream()
创建流,然后通过gateway.getDevices()
展平flatMap
返回的序列。
然后,我们执行一个filter
操作,其作用类似于您代码中的if
语句,最后,执行一个forEach
终端操作,使我们能够在每一个上调用reconnect
设备通过了过滤操作。