Home > database >  Java Lists alternate for nested forEach
Java Lists alternate for nested forEach

Time:11-22

Below is my working code set of nested forEach. Looking for the best alternate to make code clean. Looks to be a very complex set of code

This Model1 is a List containing various SubList and other few elements

List<Model1> listModel1 = getDataForModel1(......);
listModel1.getSubList1().forEach(dataSubList1 -> {
    dataSubList1.getChildSublList2().forEach(dataChildSubList2 -> {
        dataChildSubList2.getChildSubList3().forEach(dataChildSubList3 -> {
          if (dataChildSubList3.getIsValid()) {
              // Setting my required data in this dataChildSubList3 all properties
            }
        })
    })
})

The above code is working as expected but Looking for an alternate to forEach. Thus making the above code less complex. Thanks in advance

CodePudding user response:

It's hard to tell by your original question if you need the lists on the top layer. If all you need is the list of dataChildSubList3 you could do this:

List<Model1> listModel1 = getDataForModel1(......);
listModel1.getSubList1()
.stream()
.flatMap(dataSubList1 -> dataSubList1.getChildSublList2().stream())
.flatMap(dataSubList2 -> dataSubList2.getChildSublList3().stream())
.filter(dataSubList3::getIsValid)
.forEach(dataChildSubList3 -> {
          // Setting my required data in this dataChildSubList3 all 
    })

CodePudding user response:

This answer should be seen as a sketch. Since the code does not explicitly define the return types, the code might not work 1:1.


In the following, I assume that:

  • listModel1.getSubList1() returns a List<Data1>,
  • dataSubList1.getChildSublList2() returns a List<Data2>, and
  • dataSubList2.getChildSublList3() returns a List<Data3>.

If we use Java 8 , we can utilize the stream API:

List<Model1> listModel1 = getDataForModel1(......);
listModel1.getSubList1().stream()

    // 1st block replaces 1st foreach:
    .filter(Objects::nonNull)  // remove nulls, just to be safe
    .map(Data1::getChildSublList2) // transform each Data1-object to its list of Data2-objects
    .flatMap(List::stream) // flatten: transform each list in a stream of its elements

    // 2nd block replaces 2nd foreach:
    .filter(Objects::nonNull) // remove nulls, just to be safe
    .map(Data2::getChildSublList3) // transform each Data2-object to its list of Data3-objects
    .flatMap(List::stream) // flatten: transform each list in a stream of its elements

    // 3rd block replaces 3rd foreach:
    .filter(Objects::nonNull) // remove nulls, just to be safe
    .filter(Data3::getIsValid) // move if-condition to here
    .forEach(dataChildSubList3 -> {
        // Setting my required data in this dataChildSubList3 all properties
    });

It would be even better if we move the lambda-body of the forEach-lambda in a separate method (e.g. named foo) that takes a Data3 as parameter and does the processing, this would simplify the forEach(...) to:

listModel1.getSubList1().stream()
    ...
    .forEach(this::foo);
  • Related