Search code examples
javajava-8java-streamdtomutable

Removing element from an array list within a DTO using java 8 Streams


I have DTO which contains several attributes on which is of type ArrayList.

  1. I want take this DTO as parameter.
  2. Then get the attribute with ArrayList.
  3. Then based some predicate I want to remove some elements from the ArrayList
  4. Finally return the modified DTO

    public class SomeDTO{
    
    private String attrOne;
    private String attrTwo;
    private List<SomeOtherDataType> listAttr;
    // getters 
    // setter
    ...
    
    
    }
    
    // This is the method where I want to modify the DTO
    private void modifyDTO(SomeDTO someDTO){
    
     someDTO.getlistAttr()
       .stream()
       /// need help here, how to remove some element from list 
       /// based on some condition.
       /// note the changes in the list should be reflected in DTO 
    
    }
    

    This can be done by simply doing a forEach terminal operation but is there a better way to this or any best practise that others follow.

Thanks


Solution

  • in fact you have two ways :

    • collecting a new List with the elements to keep and assign it to the field

    • removing element from the actual List

    The second way is probably what you need for multiple reasons such :

    • generally for a List field you don't want to create a new List to change its state. You want to that only for fields that refer to immutable objects.

    • if some objects keep a reference on the List field, these objects will refer the old object. Which is not desirable and can create side effect issues hard to understand.

    • creating the whole filtered objects may have a cost in terms of CPU/memory while removing objects from the existing List is very probably more efficient.

    1 way) Reassign to a new object

     List<SomeOtherDataType> listAttr =
     someDTO.getlistAttr()
            .stream()
            .filter(o -> conditionToKeep)
            .collect(Collectors.toList());
    someDTO.setListAttr(listAttr);
    

    2 way) Filter in the current object

    someDTO.getlistAttr().removeIf(o -> conditionToRemove);
    

    Edit about the OP comment

    Even if the condition to filter out element requires to dig on the SomeOtherDataType object and the elements that compose it , the stream is still not required.
    A fancy code to illustrate that :

    someDTO.getlistAttr()
           .removeIf(o -> {
                            Bar bar = o.getFoo().getBar();
                            if (bar != null){
                                List<FooBar> fooBars = bar.getList(); 
                                if (fooBars.contains(...)){
                                     return true; // I remove in this case
                                }
                            }
                            return false; // in any other case I keep
                          }
                    );