Distinct by Property in Java 8 Stream

Sheeraz Gul 12 Oktober 2023
  1. Distinct by Property in Java 8 Stream
  2. Verwenden Sie Collectors.toMap, um die Distinct by Property in Java anzuwenden
  3. Verwenden Sie eine Wrapper-Klasse, um die Distinct by-Eigenschaft in Java anzuwenden
  4. Verwenden Sie die distinctByKey-Methode, um die Distinct by-Eigenschaft in Java anzuwenden
Distinct by Property in Java 8 Stream

Dieses Tutorial demonstriert die unterschiedliche Funktionalität nach Eigenschaften unter Verwendung des Streams in Java.

Distinct by Property in Java 8 Stream

Der Java 8 Stream hat eine Methode distinct(), die die Duplikate aus einer Liste herausfiltert. Diese Methode verwendet die equal-Methode der Instanz, um die eindeutigen Elemente zu überprüfen, und entfernt sie, wenn sie Duplikate erkennt.

Wir können die distinct()-Methode nicht verwenden, wenn sie auf eine bestimmte Eigenschaft oder ein bestimmtes Feld angewendet werden muss. Aber wir können die Methode distinct() pro Eigenschaft auf eine bestimmte Weise anwenden.

Versuchen wir ein Beispiel, in dem wir eine Klasse Employee erstellen, die den Namen und die ID des Mitarbeiters enthält, und dann versuchen, die Methode distinct() im Stream auf der Klassenliste Employee zu verwenden:

package delftstack;

import java.util.List;
import java.util.Objects;

class Employee {
  private String Employee_Name;
  private int Employee_ID;

  public Employee(String Employee_Name, int Employee_ID) {
    this.Employee_Name = Employee_Name;
    this.Employee_ID = Employee_ID;
  }

  public String getName() {
    return Employee_Name;
  }

  public int getID() {
    return Employee_ID;
  }

  @Override
  public boolean equals(Object Demo_Object) {
    if (this == Demo_Object) {
      return true;
    }
    if (Demo_Object == null) {
      return false;
    }
    if (getClass() != Demo_Object.getClass()) {
      return false;
    }
    Employee other = (Employee) Demo_Object;
    return Objects.equals(Employee_Name, other.Employee_Name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(Employee_Name);
  }

  @Override
  public String toString() {
    return Employee_Name + " " + Employee_ID;
  }
}

public class Example {
  public static void main(String[] args) {
    List<Employee> Employee_List =
        List.of(new Employee("Sheeraz", 10), new Employee("John", 20), new Employee("Sheeraz", 30),
            new Employee("Robert", 40), new Employee("Jake", 50), new Employee("Logan", 60));
    // the distinct() will remove the duplicates by equals
    Employee_List.stream().distinct().forEach(System.out::println);
  }
}

Der obige Code verwendet die Methode distinct() für eine Liste von Employee-Klassen, die den Stream verwenden, und löscht die Einträge mit denselben Werten. Der Code zeigt die einfache Verwendung der Methode distinct().

Sehen wir uns nun an, wie man in Java eindeutige Logik nach Eigenschaft anwendet.

Verwenden Sie Collectors.toMap, um die Distinct by Property in Java anzuwenden

Wir können die Collectors.toMap verwenden, um die Elemente eines Baches in einer Karte zu sammeln, die nach der Eigenschaft oder dem Feld verschlüsselt wird. Die Karte kann nur einen Wert für einen Schlüssel haben, also müssen wir das erste Stream-Objekt für jeden Schlüssel auswählen.

Wir können values() aus der resultierenden Karte aufrufen, die die eindeutige Logik anwendet und uns die eindeutigen Werte durch eine von uns gruppierte benutzerdefinierte Eigenschaft liefert. Sehen wir uns ein Beispiel an:

package delftstack;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

class Employee {
  private String Employee_Name;
  private int Employee_ID;

  public Employee(String Employee_Name, int Employee_ID) {
    this.Employee_Name = Employee_Name;
    this.Employee_ID = Employee_ID;
  }

  public String getName() {
    return Employee_Name;
  }

  public int getID() {
    return Employee_ID;
  }

  @Override
  public boolean equals(Object Demo_Object) {
    if (this == Demo_Object) {
      return true;
    }
    if (Demo_Object == null) {
      return false;
    }
    if (getClass() != Demo_Object.getClass()) {
      return false;
    }
    Employee other = (Employee) Demo_Object;
    return Objects.equals(Employee_Name, other.Employee_Name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(Employee_Name);
  }

  @Override
  public String toString() {
    return Employee_Name + " " + Employee_ID;
  }
}

public class Example {
  public static void main(String[] args) {
    List<Employee> Employee_List =
        List.of(new Employee("Sheeraz", 10), new Employee("John", 20), new Employee("Sheeraz", 30),
            new Employee("Robert", 40), new Employee("Jake", 50), new Employee("Logan", 60));

    Collection<Employee> Unique_EmployeeList =
        Employee_List.stream()
            .collect(Collectors.toMap(
                Employee::getName, Function.identity(), (Employee1, Employee2) -> Employee1))
            .values();
    System.out.println(Unique_EmployeeList);
  }
}

Der obige Code wendet die eindeutige Logik auf den Stream an, indem er die Methode Collection.toMap basierend auf der Eigenschaft Employee_Name verwendet, was bedeutet, dass der Code eine Liste mit eindeutigen Mitarbeiternamen zurückgibt. Siehe Ausgabe:

[Jake 50, Logan 60, Robert 40, John 20, Sheeraz 10]

Wie wir sehen können, enthält die Liste Employee zwei Einträge mit dem Namen Sheeraz, und einer davon wurde gelöscht, weil wir basierend auf der name-Eigenschaft eindeutig angewendet haben.

Verwenden Sie eine Wrapper-Klasse, um die Distinct by-Eigenschaft in Java anzuwenden

Wir können auch eine Wrapper-Klasse erstellen, der Klasse Employee Eigenschaften zuweisen und dann die Methode distinct() per Eigenschaft aus der Wrapper-Klasse anwenden. Die Wrapper-Klasse ist privat statisch und wird in der Treiberklasse deklariert.

Siehe Beispiel:

package delftstack;

import java.util.List;
import java.util.Objects;

class Employee {
  private String Employee_Name;
  private int Employee_ID;

  public Employee(String Employee_Name, int Employee_ID) {
    this.Employee_Name = Employee_Name;
    this.Employee_ID = Employee_ID;
  }

  public String getName() {
    return Employee_Name;
  }

  public int getID() {
    return Employee_ID;
  }

  @Override
  public boolean equals(Object Demo_Object) {
    if (this == Demo_Object) {
      return true;
    }
    if (Demo_Object == null) {
      return false;
    }
    if (getClass() != Demo_Object.getClass()) {
      return false;
    }
    Employee other = (Employee) Demo_Object;
    return Objects.equals(Employee_Name, other.Employee_Name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(Employee_Name);
  }

  @Override
  public String toString() {
    return Employee_Name + " " + Employee_ID;
  }
}

public class Example {
  private static class EmployeeWrapper {
    private Employee Employee;
    private EmployeeWrapper(Employee Employee) {
      this.Employee = Employee;
    }
    public Employee getEmployee() {
      return Employee;
    }
    @Override
    public boolean equals(Object Demo_Object) {
      if (this == Demo_Object) {
        return true;
      }
      if (Demo_Object == null) {
        return false;
      }
      if (getClass() != Demo_Object.getClass()) {
        return false;
      }
      EmployeeWrapper other = (EmployeeWrapper) Demo_Object;
      return Objects.equals(Employee.getName(), other.Employee.getName());
    }
    @Override
    public int hashCode() {
      return Objects.hash(Employee.getName());
    }
  }

  public static void main(String[] args) {
    List<Employee> Employee_List =
        List.of(new Employee("Sheeraz", 10), new Employee("John", 20), new Employee("Sheeraz", 30),
            new Employee("Robert", 40), new Employee("Jake", 50), new Employee("Logan", 60));

    Employee_List.stream()
        .map(EmployeeWrapper::new)
        .distinct()
        .map(EmployeeWrapper::getEmployee)
        .forEach(System.out::println);
  }
}

Der obige Code verwendet die Wrapper-Klasse EmployeeWrapper mit der Methode distinct() aus dem Stream, um die Liste der Mitarbeiter mit eindeutigen Namen zu erhalten. Wir können sehen, dass wir in der Wrapper-Klasse den Eigenschaftsnamen in der Methode equals() zugewiesen haben und ihn dann in der Treiberklasse verwenden.

Siehe die Ausgabe:

Sheeraz 10
John 20
Robert 40
Jake 50
Logan 60

Verwenden Sie die distinctByKey-Methode, um die Distinct by-Eigenschaft in Java anzuwenden

Bei dieser Methode müssen wir die gleichzeitige Hash-Map verwenden, um herauszufinden, ob es einen vorhandenen Schlüssel mit demselben Wert gibt. Diese Methode wird in der Treiberklasse deklariert und dann im Stream mit der Methode filter() verwendet.

Siehe das Beispiel:

package delftstack;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

class Employee {
  private String Employee_Name;
  private int Employee_ID;

  public Employee(String Employee_Name, int Employee_ID) {
    this.Employee_Name = Employee_Name;
    this.Employee_ID = Employee_ID;
  }

  public String getName() {
    return Employee_Name;
  }

  public int getID() {
    return Employee_ID;
  }

  @Override
  public boolean equals(Object Demo_Object) {
    if (this == Demo_Object) {
      return true;
    }
    if (Demo_Object == null) {
      return false;
    }
    if (getClass() != Demo_Object.getClass()) {
      return false;
    }
    Employee other = (Employee) Demo_Object;
    return Objects.equals(Employee_Name, other.Employee_Name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(Employee_Name);
  }

  @Override
  public String toString() {
    return Employee_Name + " " + Employee_ID;
  }
}

public class Example {
  public static <T> Predicate<T> distinctByKey(Function<? super T, Object> Key_Extractor) {
    Map<Object, Boolean> Employee_Map = new ConcurrentHashMap<>();
    return t -> Employee_Map.putIfAbsent(Key_Extractor.apply(t), Boolean.TRUE) == null;
  }

  public static void main(String[] args) {
    List<Employee> Employee_List =
        List.of(new Employee("Sheeraz", 10), new Employee("John", 20), new Employee("Sheeraz", 30),
            new Employee("Robert", 40), new Employee("Jake", 50), new Employee("Logan", 60));

    // Get distinct objects by one key
    List<Employee> Distinct_Employees1 =
        Employee_List.stream().filter(distinctByKey(p -> p.getName())).collect(Collectors.toList());
    System.out.println(Distinct_Employees1);

    // Get distinct objects by one key
    List<Employee> Distinct_Employees2 =
        Employee_List.stream()
            .filter(distinctByKey(p -> p.getName() + " " + p.getID()))
            .collect(Collectors.toList());
    System.out.println(Distinct_Employees2);
  }
}

Der obige Code versucht, die unterschiedlichen Elemente basierend auf dem Namen und wiederum dem Namen und der ID abzurufen. Siehe die Ausgabe:

[Sheeraz 10, John 20, Robert 40, Jake 50, Logan 60]
[Sheeraz 10, John 20, Sheeraz 30, Robert 40, Jake 50, Logan 60]

Wie wir sehen können, unterscheidet sich die erste Liste nur durch die name-Eigenschaft und die zweite durch die name- und ID-Eigenschaften.

Sheeraz Gul avatar Sheeraz Gul avatar

Sheeraz is a Doctorate fellow in Computer Science at Northwestern Polytechnical University, Xian, China. He has 7 years of Software Development experience in AI, Web, Database, and Desktop technologies. He writes tutorials in Java, PHP, Python, GoLang, R, etc., to help beginners learn the field of Computer Science.

LinkedIn Facebook

Verwandter Artikel - Java Stream