Java 8 Distinct Example

By Arvind Rai, September 04, 2017
On this page we will provide Java 8 Stream distinct() example. distinct() returns a stream consisting of distinct elements of that stream. distinct() is the method of Stream interface. distinct() uses hashCode() and equals() methods to get distinct elements. Hence our class must implement hashCode() and equals() methods. If distinct() is working on ordered streams, then for duplicated elements, the elements appearing first in encounter order is preserved and in this way selection of distinct element is stable. In case of unordered streams, the selection of distinct elements is not necessarily stable and can change. distinct() performs stateful intermediate operation.
In case of parallel pipelines for ordered stream, preserving stability for distinct() is expensive because it needs substantial buffering overheads. If consistency with encounter order is not necessary, then we should use unordered streams that can be achieved by using BaseStream.unordered() method.
Now we will provide examples of Stream distinct() method.

1. Stream.distinct()

Find the declaration of distinct() method.
Stream<T> distinct() 
It is the method of Stream interface. Now find the example. In this example we have a list of string data type that contains duplicate elements.
DistinctSimpleDemo.java
package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DistinctSimpleDemo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("AA", "BB", "CC", "BB", "CC", "AA", "AA");
        long l = list.stream().distinct().count();
        System.out.println("No. of distinct elements:"+l);
        String output = list.stream().distinct().collect(Collectors.joining(","));
        System.out.println(output);
    }
} 
Output
No. of distinct elements:3
AA,BB,CC 

2. Stream.distinct() with List of Objects

In this example we have a list of user object. The class will override hashCode() and equals() in order to get distinct elements.
Book.java
package com.concretepage;
public class Book {
    private String name;
    private int price;
    public Book(String name, int price) {
	this.name = name;
	this.price = price;
    }
    public String getName() {
	return name;
    }
    public int getPrice() {
	return price;
    }
    @Override
    public boolean equals(final Object obj) {
      if (obj == null) {
         return false;
      }
      final Book book = (Book) obj;
      if (this == book) {
         return true;
      } else {
         return (this.name.equals(book.name) && this.price == book.price);
      }
    }
    @Override
    public int hashCode() {
      int hashno = 7;
      hashno = 13 * hashno + (name == null ? 0 : name.hashCode());
      return hashno;
    }
} 
DistinctWithUserObjects.java
package com.concretepage;
import java.util.ArrayList;
import java.util.List;
public class DistinctWithUserObjects {
    public static void main(String[] args) {
        List<Book> list = new ArrayList<>();
        {
           list.add(new Book("Core Java", 200));
           list.add(new Book("Core Java", 200));
           list.add(new Book("Learning Freemarker", 150));        	
           list.add(new Book("Spring MVC", 300));
           list.add(new Book("Spring MVC", 300));
        }
        long l = list.stream().distinct().count();
        System.out.println("No. of distinct books:"+l);
        list.stream().distinct().forEach(b -> System.out.println(b.getName()+ "," + b.getPrice()));
    }
} 
Output
No. of distinct books:3
Core Java,200
Learning Freemarker,150
Spring MVC,300 

3. Distinct by Property

distinct() does not provide distinct elements by property or key. It works on the basis of hashCode() and equals(). If we want distinct element by a property or key, we can achieve it by a work around code. Find the code snippet.
static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
} 
The above code can be used with Stream filter() method as follows.
list.stream().filter(distinctByKey(b -> b.getName())); 
Now look into the distinctByKey() method. This method returns Predicate instance that maintains state about what is seen previously using ConcurrentHashMap.
Find a complete example using distinctByKey() method to get distinct elements of our stream by class property.
DistinctByProperty.java
package com.concretepage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
public class DistinctByProperty {
    public static void main(String[] args) {
        List<Book> list = new ArrayList<>();
        {
        	list.add(new Book("Core Java", 200));
        	list.add(new Book("Core Java", 300));
        	list.add(new Book("Learning Freemarker", 150));
        	list.add(new Book("Spring MVC", 200));
        	list.add(new Book("Hibernate", 300));
        }
        list.stream().filter(distinctByKey(b -> b.getName()))
              .forEach(b -> System.out.println(b.getName()+ "," + b.getPrice()));   
    }
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
} 
Output
Core Java,200
Learning Freemarker,150
Spring MVC,200
Hibernate,300 

References

Java Doc - Interface Stream
Stackoverflow.com - Java 8 Distinct by property

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us