How to get Java 8 Distinct value by property

The Java 8 Stream supports various functionalities to handle aggregate operations in a sequence of elements.

You can use Java 8 Stream’s distinct function.stream().distinct() to aggregate distinct values in a stream of elements.

In this tutorial, you will learn how to identify the distinct elements by property using Java 8.

Using Custom Object property

To get distinct value by property in a Java object,

  • Iterate through the stream of objects and filter the stream(stream.filter(predicateFn)) based on a property by passing a predicate function.
  • Predicate function should pass the property as input(car->car.getDoors()) and will use a ConcurrentHashMap to hold the distinct value.
  • Any element in the stream is first checked in the map(map.putIfAbsent()); if the element is not found, that value will be added to the map and returned. If a specific element is already present in the map, it will not be added to the map and not returned; by this, distinct values are retained.
  • Convert the stream to a List using .collect().

Use this method when distinct values are expected based on specific field/property in an object.

Code

    import com.techmam.model.Car;
    import java.util.Arrays;   
    import java.util.List;  
    import java.util.concurrent.ConcurrentHashMap;  
    import java.util.function.Function;  
    import java.util.function.Predicate;  
    import java.util.stream.Collectors; 

    //main
    public static void main(String[] args) {
        List<Car> carsList = Arrays.asList(new Car("Camaro ZL1",2),  
        new Car("Mustang",2),  
        new Car("AMG C63",2),  
        new Car("Mini Hatch", 3),  
        new Car("M3 Saloon", 4),  
        new Car("S4 Saloon", 4),  
        new Car("Taycan",4));  

        List<Car> distinctCars = carsList.stream().filter(distinctObjectsByProperty(car->car.getDoors())).collect(Collectors.toList());  
        distinctCars.forEach(e->{  
            System.out.println("Model: "+e.getName()+", No of Doors: "+e.getDoors());
        });
    }

    //private method to filter the distinct value
    private static <T> Predicate<T> distinctObjectsByProperty(Function<? super T, ?> key) {  
        Map<Object, Boolean> distinctValues = new ConcurrentHashMap<>();  
        return t -> distinctValues.putIfAbsent(key.apply(t), Boolean.TRUE) == null;  
    }

    //Car.java
    import lombok.AllArgsConstructor;  
    import lombok.Data;  

    @AllArgsConstructor  
    @Data  
    public class Car {  
        String name;  
        int doors;  
    }

Output

    Model: Camaro ZL1, No of Doors: 2
    Model: Mini Hatch, No of Doors: 3
    Model: M3 Saloon, No of Doors: 4

Using Collectors.toMap()

To get a distinct value from a property using Collectors.toMap(),

  • Convert the list to stream using .stream().
  • Use the .collect(Collectors.toMap()) method to convert the stream of elements to a Map.
  • The .toMap() accepts a property as key (Car::getDoors), the current object(Function.identity()) as value and a merger function((car1, car2) -> car1).
  • The merger function will internally use a HashMap to store each element when already not present, and that map is returned.
  • Use the map.values() method to return only the distinct objects.

Use this method when the distinct values are required as a map with key-value pair based on the property.

Code

    import com.techmam.model.Car;  

    import java.util.Arrays;  
    import java.util.Collection;  
    import java.util.List;  
    import java.util.function.Function; 

    //main
    List<Car> carsList = Arrays.asList(new Car("Camaro ZL1",2),  
    new Car("Mustang",2),  
    new Car("AMG C63",2),  
    new Car("Mini Hatch", 3),  
    new Car("M3 Saloon", 4),  
    new Car("S4 Saloon", 4),  
    new Car("Taycan",4));  

    Collection<Car> distinctCars = carsList.stream()  
        .collect(Collectors.toMap(Car::getDoors, Function.identity(),  (car1, car2) -> car1)).values();  
    System.out.println(distinctCars);  

Output

    [Car(name=Camaro ZL1, doors=2), Car(name=Mini Hatch, doors=3), Car(name=M3 Saloon, doors=4)]

Distinct in Duplicate Objects

To Identify distinct values in a list of duplicate objects,

  • Iterate the stream and invoke the distinct method(.distinct) method.
  • All the exact match duplicate values will be removed, and distinct stream values will be returned.
  • Convert the stream as list using .collect(Collectors.toList()) to get the distinct objects.

Use this method to identify the duplicate objects in a List.

Code

    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;

    List<Car> carsListWithDuplicates = Arrays.asList(new Car("Mustang",2),  
    new Car("Mustang",2),  
    new Car("Mustang",2),  
    new Car("Mini Hatch", 3),  
    new Car("M3 Saloon",4),  
    new Car("M3 Saloon",4),  
    new Car("M3 Saloon",4));  

    // Get distinct people by id  
    List<Car> distinctCars = carsListWithDuplicates.stream()
        .distinct().collect(Collectors.toList());  

    System.out.println(distinctCars);

Output

    [Car(name=Mustang, doors=2), Car(name=Mini Hatch, doors=3), Car(name=M3 Saloon, doors=4)]

Distinct in Duplicate Values

To get a list of distinct values in a stream of objects,

  • Iterate the stream and invoke .map(property) with the property.
  • Use the .distinct() method to return only the distinct property values.
  • Convert the distinct stream of values to List using ..collect(Collectors.toList().

Use this method to find distinct values of an object property.

Code

    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;

    //main
    List<Car> carsList = Arrays.asList(new Car("Camaro ZL1",2),  
    new Car("Mustang",2),  
    new Car("AMG C63",2),  
    new Car("Mini Hatch", 3),  
    new Car("M3 Saloon", 4),  
    new Car("S4 Saloon", 4),  
    new Car("Taycan",4));  

    List<Integer> distinctCarDoorValues= carsList.stream().map(Car::getDoors).distinct().collect(Collectors.toList());
    distinctCarDoorValues.forEach(System.out::println);

Output

2
3
4

The below examples explain getting distinct values in an Integer stream

Use this method for any primitive datatype streams.

    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;

    //main
    Stream<Integer> numbersStream = Stream.of(3,4,5,6,3,4,6,7,4,5,6,7);  
    List<Integer> distinctNumbers = numbersStream.distinct().collect(Collectors.toList());  
    System.out.println(distinctNumbers);

Output

    [3, 4, 5, 6, 7]

Related Topics

Leave a Comment