Search code examples
javajava-8java-streampass-by-referencereduce

reduce() operation on stream seems to be modifying the source of data (list) Stream API Java 8


I have a simple POJO called Transaction with three private properties String type,double amount and String id. In main class,I created few instances of Transaction calling the constructor as written below -

List<Transaction> transList = Arrays.asList(new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,45.50,"2a"),
                                            new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,50.0,"1a"),
                                            new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,15.00,"3a"),
                                            new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,27.43,"4a"),
                                            new Transaction(Transaction.TRANSACTION_TYPE_CLOTHING,145.0,"5a"),
                                            new Transaction(Transaction.TRANSACTION_TYPE_CLOTHING,105.0,"6a"));

Now I have called below operation on this listusing below code -

Optional<Transaction> totalA = transList.stream()
.filter(x->x.getType()==Transaction.TRANSACTION_TYPE_GROCERY)
.reduce((a,b) -> {Transaction z = b;                                                                             
                  z.setAmount(a.getAmount()+b.getAmount());
                  return z;});

Here I have tried to perform reduction operation by keeping Transaction as the lowest unit and calculate the sum of all transaction amounts and set it inside a new Transaction z. All this gets stored finally as Optional. After this, if I try to carry out any other operation on the transList data source,I get incorrect results as the state of transList gets disrupted.

List<String> transactionIds = transList.stream()
                                                .filter(x -> x.getAmount()>50.00)
                                                .map(Transaction::getId)
                                                .collect(Collectors.toList());
System.out.println(transactionIds);

I have done the Optional containing Double item and double return value implementations successfully for this list using reduce(). All I want to know is what is so wrong with the Optional that it ends up modifying the source of data itself, which should not happen as Stream is functional.


Solution

  • The lambda:

    (a,b) -> {Transaction z = b;                                                                             
                      z.setAmount(a.getAmount()+b.getAmount());
                      return z;}
    

    Is modifying the b parameter. Keep in mind that an assignement does not copy an object so Transaction z = b is just giving an alias to the object pointed to by b.

    You should probably use the reduce overload that allows to specify the identity and combiner, os just create a copy of the object.