0

I have a method which receives an object as parameter that contains a list (firstList) and sublist (secondList) of elements, in which I need to add a new element to the firstList with the resulting value of the subtraction of another two elements contained in the secondList that may be identified by one Enum property value that they have.

Here's an example of the code I have right now:

private void calculateAndAddResultingObject(final MainObject mainObject) {
    List<AnObject> firstList = mainObject.getList();

    for (AnObject anObject : firstList) {

        List<AnotherObject> secondList = anObject.getSublist();

        BigDecimal firstOperand = secondList.stream()
                .filter(anotherObject -> Enum.VALUE1.equals(anotherObject.getCode())).findAny()
                .orElse(new AnotherObject(Enum.VALUE1, BigDecimal.ZERO, mainObject.getProperty()))
                .getValue();

        BigDecimal secondOperand = secondList.stream()
                .filter(anotherObject -> Enum.VALUE2.equals(anotherObject.getCode())).findAny()
                .orElse(new AnotherObject(Enum.VALUE2, BigDecimal.ZERO,
                        mainObject.getProperty())).getValue();

        BigDecimal resultingValue = BigDecimal.ZERO;

        if (firstOperand.compareTo(secondOperand) > 0) {
            resultingValue = firstOperand.subtract(secondOperand);
        }

        secondList
                .add(new AnotherObject(Enum.VALUE2, resultingValue, mainObject.getProperty()));
    }
}

How may I reduce the number of iterations to improve performance? Is it possible to do this in a single operation?

Thanks!

Always Learning
  • 5,510
  • 2
  • 17
  • 34
lo_ol
  • 35
  • 6
  • Performance is not the same as complexity, start by reading [How do I write a correct micro-benchmark in Java?](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) – Karol Dowbecki May 22 '20 at 14:37
  • Is `AnotherObject.getValue()` equal to the BigDecimal that is given to `AnotherObject`'s constructor at creation? You might improve the code by creating less objects. Also, replacing streams with for loops might improve performance in this case. (see https://stackoverflow.com/questions/24054773/java-8-streams-multiple-filters-vs-complex-condition) – sapisch May 22 '20 at 15:14

1 Answers1

0

Assuming that an object in the sublist can equal either Enum.VALUE1 or Enum.VALUE2 (not both for the same AnotherObject) and that the BigDecimal that is given to an AnotherObjet's constructor is equal with AnotherObject.getValue(), you can reduce the Objects being created and remove one stream:

void calculateAndAddResultingObject(final MainObject mainObject) {
    List<AnObject> firstList = mainObject.getList();

    for (AnObject anObject : firstList) {
        List<AnotherObject> secondList = anObject.getSublist();
        final BigDecimal value = calculateSublist(secondList);
        secondList.add(new AnotherObject(Enum.VALUE2, value, mainObject.getProperty()));
    }
}

private BigDecimal calculateSublist(final List<AnotherObject> list) {
    BigDecimal firstOperand = null, secondOperand = null;

    for (AnotherObject object : list) {
        if (firstOperand == null && Enum.VALUE1.equals(object.getCode())) {
            firstOperand = object.getValue();
        } else if (secondOperand == null && Enum.VALUE2.equals(object.getCode())) {
            secondOperand = object.getValue();
        } else if (firstOperand != null && secondOperand != null) { // If firstOperand and secondOperand found, break the loop
            break;
        }

    }
    if (firstOperand == null) firstOperand = BigDecimal.ZERO;
    if (secondOperand == null) secondOperand = BigDecimal.ZERO;

    if (firstOperand.compareTo(secondOperand) > 0) {
        return firstOperand.subtract(secondOperand);
    }
    return BigDecimal.ZERO;
}

Now you have one less stream that is being created. Nevertheless, you have to create a microbenchmark to test weather this change really improved the performance in your case. It depends on the size and the quantity of your objects.

sapisch
  • 535
  • 3
  • 14
  • Thanks a lot! Your solution seems better. I will try to reproduce it with a microbenchmark to see the difference. :) – lo_ol May 22 '20 at 17:31
  • Just a question in terms of performance, for loops are the best there is to iterate through lists? Why did they wasted times inventing streams then? :/ Sorry for this amateur questions I am new to software development. – lo_ol May 22 '20 at 17:36
  • You're welcome! If my answer answers your question, I would be happy if you marked it as a solution. If you would want to improve the performance of your calculation even more at large dimensions, you might consider calculating the sublists asynchroniously. – sapisch May 22 '20 at 17:37
  • You can find more about "Streams vs for loops" here -> https://stackoverflow.com/questions/44180101/in-java-what-are-the-advantages-of-streams-over-loops – sapisch May 22 '20 at 17:38