javajava-streamremove-if

Removing elements of one list if present in another list using stream


I didn't find any thread here on this Question. I am trying to Remove elements (Cars in my case) of one list (cars1) if they present in another list (cars2) using Java stream.

I tried using removeIf but then it felt like it works more appropriately with List of Strings, etc. instead of objects.

Imagine the sample codes below:

    Car c1 = new Car();
    c1.id = 1;
    c1.name = "C1";

    Car c2 = new Car();
    c2.id = 2;
    c2.name = "C2";

    List<Car> cars1 = new ArrayList<Car>();
    cars1.add(c1);
    cars1.add(c2);

    List<Car> cars2 = new ArrayList<Car>();
    cars2.add(c2);

    // TODO : Remove all the cars from cars1 list that are in cars2 list using java streams

How to remove all the cars from cars1 list that are present in cars2 list using java streams?


Solution

  • If methods hashCode and equals are properly implemented in class Car, the stream-based solutions may look as follows:

    // Predicate.not added in Java 11
    List<Car> notJava11 = cars1.stream()
                            .filter(Predicate.not(cars2::contains))
                            .collect(Collectors.toList());
    
    List<Car> notIn2 = cars1.stream()
                            .filter(car -> !cars2.contains(car))
                            .collect(Collectors.toList());
    
    
    cars2.forEach(cars1::remove); 
    // no need to call cars2.stream().forEach(cars1::remove);
    

    Here the first occurrence of Car instance is removed in cars1

    cars1.removeIf(cars2::contains);
    

    If you due to some reason equals/hashCode are not overridden in class Car, the following solution may be offered:

    List<Car> notIn2 = cars1
            .stream()
            .filter(c1 -> cars2
                .stream()
                .noneMatch(c2 -> 
                     c1.getId() == c2.getId()
                     && Objects.equals(c1.getName(), c2.getName())
                )
            )
            .collect(Collectors.toList());
    
    cars1.removeIf(c1 -> cars2
        .stream()
        .anyMatch(c2 -> c1.getId() == c2.getId() 
            && Objects.equals(c1.getName(), c2.getName())
        )
    );