PeeCee
PeeCee

Reputation: 23

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.

Upvotes: 2

Views: 113

Answers (3)

Ruslan
Ruslan

Reputation: 6290

It is everything ok with the Optional. Your object is a reference data type. Here you copied the reference of your object Transaction z = b;. It doesn't create a new one. Now both variables point at the same Transaction. And no matter what you modify z or b it ends up modifying the source data

This might be useful https://javarevisited.blogspot.com/2015/09/difference-between-primitive-and-reference-variable-java.html

Upvotes: 0

dehasi
dehasi

Reputation: 2773

Transaction z = b;// doesn't create a new object.  
                                                    z.setAmount(a.getAmount()+b.getAmount()); //you actually set a amout to `b` object

return z; // and here you returm `b` object 

Upvotes: 1

Giacomo Alzetta
Giacomo Alzetta

Reputation: 2479

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.

Upvotes: 3

Related Questions