Функция Java Stream distinct() для удаления дубликатов

Метод Java Stream distinct()возвращает новый поток различных элементов. Поэтому его можно использовать для удаления дубликатов элементов из набора.

Особенности использования метода distinct()

  • Элементы сравниваются с использованием equals(). Поэтому необходимо, чтобы элементы потока использовали правильную реализацию этого метода.
  • Если поток упорядочен, порядок нумерации сохраняется.
  • Если поток не упорядочен, то элементы потока могут иметь любой порядок.
  • Stream distinct() - промежуточная операция с состоянием.
  • Использование Different() с упорядоченным параллельным потоком может иметь низкую производительность из-за значительных расходов на буферизацию. В этом случае перейдите к последовательной обработке потока.

Удаление дублирующихся элементов с помощью distinct()

Рассмотрим, как использовать метод distinct()для удаления дубликатов из набора.

jshell> List<Integer> list = List.of(1, 2, 3, 4, 3, 2, 1);
list ==> [1, 2, 3, 4, 3, 2, 1]

jshell> List<Integer> distinctInts = list.stream().distinct().collect(Collectors.toList());
distinctInts ==> [1, 2, 3, 4]
Удаление дублирующихся элементов с помощью distinct()

Пример Java Stream distinct()

Обработка только уникальных элементов с использованием Stream distinct()и forEach()

Поскольку distinct() является промежуточной операцией, то мы можем использовать  forEach() для обработки только уникальных элементов.

jshell> List<Integer> list = List.of(1, 2, 3, 4, 3, 2, 1);
list ==> [1, 2, 3, 4, 3, 2, 1]

jshell> list.stream().distinct().forEach(x -> System.out.println("Processing " + x));
Processing 1
Processing 2
Processing 3
Processing 4
Обработка только уникальных элементов с использованием Stream distinct()и forEach()

Пример Java Stream distinct() forEach()

Применение Stream distinct() к набору пользовательских объектов

Рассмотрим простой пример использования distinct() для удаления повторяющихся элементов из списка.

package com.journaldev.java;

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

public class JavaStreamDistinct {

	public static void main(String[] args) {
		List<Data> dataList = new ArrayList<>();
		dataList.add(new Data(10));
		dataList.add(new Data(20));
		dataList.add(new Data(10));
		dataList.add(new Data(20));

		System.out.println("Data List = "+dataList);

		List<Data> uniqueDataList = dataList.stream().distinct().collect(Collectors.toList());

		System.out.println("Unique Data List = "+uniqueDataList);
	}

}

class Data {
	private int id;

	Data(int i) {
		this.setId(i);
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Override
	public String toString() {
		return String.format("Data[%d]", this.id);
	}
}

Вывод:

Data List = [Data[10], Data[20], Data[10], Data[20]]
Unique Data List = [Data[10], Data[20], Data[10], Data[20]]

distinct() не удалил дублирующиеся элементы, потому что мы не реализовали метод equals() в классе Data. Метод Object equals() суперкласса был использован для идентификации равных элементов. Реализация метода класса equals() приведена ниже:

public boolean equals(Object obj) {
    return (this == obj);
}

Поскольку объекты Date() имели одинаковые идентификаторы, но ссылались на разные объекты, они считались не равными. Вот почему важно реализовать метод equals(), если вы планируете использовать distinct() при работе с пользовательскими объектами.

Обратите внимание на то, что методы equals() и hashCode() используются классами Collection API для сравнения объектов. Так что лучше обеспечить реализацию для них обоих.

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + id;
	return result;
}

@Override
public boolean equals(Object obj) {
	System.out.println("Data equals method");
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	Data other = (Data) obj;
	if (id != other.id)
		return false;
	return true;
}

Совет: Вы можете сгенерировать метод equals() и hashCode(), используя меню Eclipse: пункт Source> Generate equals() and hashCode().

Результирующий вывод после добавления реализации equals() и hashCode():

Data List = [Data[10], Data[20], Data[10], Data[20]]
Data equals method
Data equals method
Unique Data List = [Data[10], Data[20