deepan
deepan

Reputation: 47

How to approach mutation with streams in Java

class Item {
  int id;
  List<PriceDetails> priceDetails;
  String itemName;
}
class PriceDetails {
 String price;
}

I am getting multiple items in a JSON file. I am trying to filter priceDetails with empty price (not the items, just removing all the priceDetails in the list with empty price)

NOTE : I am trying to mutate my item input just because I want all the fields in the items to be same except this priceDetails, so I am mutating the item and just trying to add a new priceDetails to the same item

I am able to write Java code, and it's working as expected, but I don't know how to write using Java Streams.

Code :

public static List<Item> filterByEmptyTicketPrice(List<Item> items) {
    List<Item> result = new ArrayList<>();
    for (Item item : items) {
        List<PriceDetails> temp = new ArrayList<>();
        for (PriceDetails priceDetails : item.priceDetails) {
            if (nonNull(priceDetails.price)) {
                temp.add(priceDetails);
            }
        }
        item.priceDetails = temp;
        result.add(item);
    }
    return result;
}

I have this stream-based code, but I want the code with mutation

public static List<Item> filterByEmptyTicketPrice(List<Item> items) {
        return items.stream()
                .map(item -> new Item(filterPrices(item.priceDetails)))
                .collect(Collectors.toList());
    }

    static List<PriceDetails> filterPrices(List<PriceDetails> priceDetailsList) {
        return priceDetailsList
                .stream()
                .filter(priceDetails -> priceDetails.price != null)
                .collect(Collectors.toList());
    }

public Item(List<PriceDetails> priceDetails) {
    this.priceDetails = priceDetails; }

The problem is here:

map(item -> new Item(filterPrices(item.priceDetails)))

It creates a new Item and I am losing all the values of other fields in the item. I don't want to lose all other fields of the item, just wanted to update the item with filtered priceDetails (if I find a null value).

Upvotes: 1

Views: 736

Answers (1)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 29058

Instead of utilizing streams, I guess you can get rid of all priceDetails containing null prices since they hardly could be useful.

You can do it by using Java 8 removeIf which is a bulk operation you can perform on any mutable collection. It'll remove all elements that match the given predicate.

items.forEach(Item -> item.getpriceDetails()
         .removeIf(priceDetail -> priceDetail.getPrice() == null));

Sidenote: don't skip the access modifier while declaring a field. And don't access the attributes directly, use getters instead. If your main background is JavaScript you might be accustomed to that, but in Java it's not a good practice. Class-members must be encapsulated within a class using access modifiers, and in order to make it possible to interact with them, you should provide limited access to them.

Upvotes: 1

Related Questions