How to avoid nested forEach calls?

  • A+

I have the following code:

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();         }     } } 

I want to refactor the code using Stream API. My first attempt was like the following:

gateways     .stream()     .forEach(         gateway -> {             gateway                 .getDevices()                 .parallelStream()                 .filter(device -> device.isDisconnected())                 .forEach(device -> device.reconnect())             ;         }     ) ; 

I didn't like it so after some modifications I ended up with this code:

gateways     .parallelStream()     .map(gateway -> gateway.getDevices().parallelStream())     .map(stream -> stream.filter(device -> device.isDisconnected()))     .forEach(stream -> stream.forEach(device -> device.reconnect())) ; 

My question is whether there is a way to avoid nested forEach.


You should flatten the stream of streams using flatMap instead of map:

gateways     .parallelStream()     .flatMap(gateway -> gateway.getDevices().parallelStream())     .filter(device -> device.isDisconnected())     .forEach(device -> device.reconnect()); 

I would improve it further by using method references instead of lambda expressions:

gateways     .parallelStream()     .map(Gateway::getDevices)     .flatMap(List::stream)     .filter(Device::isDisconnected)     .forEach(Device::reconnect); 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: