Multiple For each performance tuning

Viewed 121

I want to iterate an object which has list inside list and so on. Since this data is huge in size, I want to exit all iterations when the if condition is met.

Since break is not supported in forEach, how can we achieve this? Is there any better solution other than using forEach to increase performance? Performance is key criteria here. Can I use streams / parallel streams here?

dataList.forEach(data -> data.getList()
    .forEach(data1 -> data1.getList()
        .forEach(data2 ->data2.getList()
           .forEach(data3 ->data3.getList()
              .forEach(data4 -> {
                  if (data4.getSomeData().equals(someData)) {
                    //some logic to populate some object using data1, data2, data3 & data4 fields
                   //I want to exit all the for each iterations if this condition is met. Since this list is very huge in size
                }
            })))));
3 Answers

It is possible to do this with a lot of flatmapping stages:

Optional<YourObject> mappedData = dataList.getList().stream()
    .flatMap(data -> data.getList().stream()
      .flatMap(d1 -> d1.getList().stream()
        .flatMap(d2 -> d2.getList().stream()
          .flatMap(d3 -> d3.getList().stream()
            .flatMap(d4 -> d4.getList().stream()
              .filter(d4.getSomeData().equals(someData))
              .map(d -> mapping(data, d1, d2, d3, d4, d))))))
    ).findFirst();

Another way would be using for-each loops in a method to do the short-circuting:

private Optional<YourObject> foo(Data data) {
  for (Data d : data.getList()) {
    for (Data1 d1 : d.getList()) {
      for (Data2 d2 : d1.getList()) {
        for (Data3 d3 : d2.getList()) {
          for (Data4 d4 : d3.getList()) {
            if (d4.getSomeData().equals(someData)) {
              return Optinal.of(mapping(data, d1, d2, d3, d4));
            }
          }
        }
      }
    }
  }
  return Optional.empty();
}

or with a break statement on the most outer loop:

Optional<YourObject> yourObject = Optional.empty();
outer: for (Data d : data.getList()) {
  for (Data1 d1 : d.getList()) {
    for (Data2 d2 : d1.getList()) {
      for (Data3 d3 : d2.getList()) {
        for (Data4 d4 : d3.getList()) {
          if (d4.getSomeData().equals(someData)) {
            yourObject = Optional.of(mapping(data, d1, d2, d3, d4));
            break outer;
          }
        }
      }
    }
  }
}

Performance is very similar for - traditional for and forEach operation most of the cases. So you can use traditional for operation in that case. You can now propagate break over every loop.

Demo code:

boolean killSwitch = false;
for(;i < size && !killSwitch; i++){
   for( ;j < size && !killSwitch; j++){
       for(;k < size && !killSwitch; k++){
            if(condition == true){
                killSwitch = true;
            }
       }
   }
}
dataList.forEach(
                data -> data.forEach(
                    data1 -> data1.forEach(
                            data2 -> data2.stream().
                                    filter(data2.getSomeData().equals(someData)).
                                    findFirst().
                                    ifPresentOrElse(data2.doSomethingMethod()), () -> {
                                //do failed code
                                return 0;
                            })
                    )
        );
Related