0

I have a method like below:

  public void method ()
  {
        List<String> list1 = someOperation();
        List<List2Class> list2;
        long failedCount = 0;
        for (String element : list1) {
            try {
                list2 = someclass.method1(element);
                list2 = someclass.method2(element);
                someclass.saveToDB(list2);
            
            } catch (Exception e) {
                failedCount++;
              
            }
        }
       //some checks on failedCount
    }

I want to convert the for loop into parallel stream, can someone tell me what should be the code changes in the above method for the same? PS - method1 and method2 are returning modified version of list2.

Ap1712
  • 33
  • 4
  • 1
    It looks like `list2` is simply `someclass.method2(/* last element of list1 */)` there. Do you really need to process all the others? – Andy Turner Aug 17 '21 at 09:15
  • 1
    @AndyTurner that would be true if there was no `try ... catch`. With `try catch` it could be anything. To be more specific last that didn't fail. I doubt that it is possible to use Streams here in any meaningful way. – talex Aug 17 '21 at 09:20
  • I have updated the question to be more specific, each method is returning a modified version of list2 which is getting saved to db for each element in the for loop – Ap1712 Aug 17 '21 at 09:22
  • 1
    The result of `someclass.method1(element)` is never used. It’s overwritten with the result of `someclass.method2(element)` right in the next line. – Holger Aug 17 '21 at 11:37

1 Answers1

0

The logic here is basically "the result of the last successful operation".

Assuming you don't need the failedCount (you don't show it being used), you can do that like this: map successful operations to a present Optional, failed operations to an absent Optional; and just take the last present optional:

Optional<List<List2Class>> opt = list1.stream()
    .flatMap(element -> Stream.of(runOperation(someclass::method1, element), runOperation(someclass::method2, element))
    .reduce((a, b) -> !b.isPresent() ? a : b);

where runOperation is something like:

Optional<List<List2Class>> runOperation(Function<String, List<List2Class>> operation, String parameter) {
  try {
    return Optional.of(operation.apply(parameter));
  } catch (Exception e) {
    return Optional.absent();
  }
}

You then need to decide what value list2 should have if no operations succeed.

If you actually do need the failedCount, you can break this up a bit:

Stream<Optional<List<List2Class>>> intermediate =
    list1.stream()
        .flatMap(element -> Stream.of(runOperation(someclass::method1, element), runOperation(someclass::method2, element));

Map<Boolean, List<Optional<List<List2Class>>>> partitioned =
    intermediate.collect(Collectors.partitioningBy(Optional::isPresent));

Now partitioned.get(true) has all the successful results, while partitioned.get(false) has all the failed results. So:

Optional<List<List2Class>> opt = partitioned.get(true).stream().reduce((a, b) -> !b.isPresent() ? a : b);
long failedCount = partitioned.get(false).size();
Andy Turner
  • 137,514
  • 11
  • 162
  • 243