Java >> Programma Java >  >> Java

Comparatore con esempi di espressioni Java Lambda

Scopri come utilizzare il comparatore basato su espressioni Java Lambda per ordinare facilmente le raccolte in avanti e indietro.

Panoramica

Per ordinare una raccolta, gli elementi delle raccolte devono essere confrontati per impostazione predefinita. Quando gli elementi della raccolta appartengono a tipi di dati predefiniti Java, non è necessario fornire la logica di confronto. D'altra parte, quando abbiamo una raccolta di un oggetto personalizzato, dobbiamo fornire la strategia di confronto.

Uno dei modi per farlo è creare un Comparatore implementazione per il nostro oggetto e scrivi la logica di confronto nel compare() metodo. In questo tutorial impareremo Come possiamo utilizzare le espressioni Java Lambda per ordinare le raccolte fornendo implementazioni di comparatori inline .

Prepara una raccolta

Prepariamo prima una Collezione che ordineremo durante questo tutorial. Supponiamo che la nostra collezione contenga record di oggetti studente, dove lo Studente l'oggetto ha solo pochi campi.

public class Student {
    private final Long studentId;
    private final String firstName;
    private final String lastName;
    private final Integer age;

    // Constructor, Getter, and Setter
}Code language: Java (java)

Ora creeremo alcuni record di studenti fittizi e li inseriremo in un semplice ArrayList esempio.

Student student1 = new Student(2L, "Karl", "F", 18);
Student student2 = new Student(3L, "Jack", "P", 20);
Student student3 = new Student(5L, "Nick", "G", 17);
Student student4 = new Student(1L, "Tom", "F", 21);
Student student5 = new Student(4L, "Jon", "W", 22);

students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
students.add(student5);Code language: Java (java)

Si noti che i record nell'elenco sono in ordine casuale.

Ordina senza espressioni Lambda

Il modo base per ordinare gli elementi di un elenco consiste nell'usare sort() metodo. Tuttavia, se l'elenco contiene oggetti personalizzati, come il nostro, dobbiamo fornire un'istanza di confronto in grado di confrontare le istanze dell'oggetto personalizzato.

Il prossimo è un esempio di utilizzo dell'ordinamento di una raccolta utilizzando la classe interna anonima o l'implementazione inline di Comparator .

students.sort(new Comparator<Student>() {
  @Override
  public int compare(Student o1, Student o2) {
    return o1.getFirstName().compareTo(o2.getFirstName());
  }
});Code language: Java (java)

L'implementazione in linea di Comparator interfaccia confronta due studenti oggetti in base al campo del nome.

Student(studentId=3, firstName=Jack, lastName=P, age=20)
Student(studentId=4, firstName=Jon, lastName=W, age=22)
Student(studentId=2, firstName=Karl, lastName=F, age=18)
Student(studentId=5, firstName=Nick, lastName=G, age=17)
Student(studentId=1, firstName=Tom, lastName=F, age=21)

L'output mostra che il nostro ArrayList è ordinato in base al campo del nome di Student.

Ordina utilizzando l'espressione Lambda di base

Java Lambda Expressions, aiuta a ridurre molti blocchi di codice della piastra del builder e rende il codice conciso. Poiché il comparatore è un'Interfaccia funzionale Java , possiamo usare un'espressione lambda invece di passare una classe di implementazione inline.

students.sort(
  (o1, o2) -> o1.getFirstName().compareTo(o2.getFirstName()));Code language: Java (java)

Qui abbiamo fornito un'espressione lambda per compare() metodo del comparatore. Possiamo vedere che il codice ora è molto più pulito.

Ordina utilizzando il metodo di riferimento

Nell'esempio precedente abbiamo fornito un'implementazione inline del comparatore sotto forma di espressione lambda Java. Tuttavia, invece di mettere in linea la logica di ordinamento, possiamo inserirla in un metodo riutilizzabile e utilizzare riferimento al metodo per ordinare una raccolta in base a quella logica.

Ad esempio, creiamo una classe Student Sort Utility.

public class StudentSortUtils {

  public static int comparingFirstName(
        Student student1, 
        Student student2) {

    return student1.getFirstName()
        .compareTo(student2.getFirstName());
  }

  public static int comparingFirstAndLastName(
        Student student1, 
        Student student2) {

    return
      (student1.getFirstName().equals(student2.getFirstName()))
        ? comparingFirstName(student1, student2)
        : student1.getLastName().compareTo(student2.getLastName());
  }
}Code language: Java (java)

Qui abbiamo due versioni dei metodi di confronto. Entrambi accettano gli stessi argomenti e restituiscono lo stesso tipo di Comparator#compare() metodo. Tuttavia, hanno strategie di confronto diverse.

Ora possiamo ordinare una raccolta utilizzando Method Reference , così.

students
  .sort(StudentSortUtils::comparingFirstName);Code language: Java (java)

In alternativa, possiamo anche ordinare in base a più campi multipli , utilizzando il rispettivo metodo di riferimento.

<meta charset="utf-8">students
  .sort(StudentSortUtils::comparingFirstAndLastName);Code language: Java (java)

Ordina utilizzando il metodo di fabbrica del comparatore

Il comparatore Java interfaccia ha un metodo factory statico di comparing() . Il confronto() accetta una funzione di estrazione chiave e crea un Comparatore istanza in modo dinamico che confronta la chiave data.

Ad esempio, se vogliamo ordinare gli studenti in base all'età, possiamo creare un Comparatore usando il suo metodo di fabbrica statico comparing() così:

Comparator.comparing(student -> student.getAge())Code language: Java (java)

Tuttavia, le espressioni Java Lambda ci consentono di sostituire l'espressione lambda con un riferimento diretto al metodo.

students.sort(Comparator.comparing(Student::getAge));Code language: Java (java)

Ordinamento in base a più campi

Quando vogliamo ordinare una raccolta in base a più campi, possiamo semplicemente creare una composizione di più espressioni condizionali. Ad esempio, per ordinare la raccolta degli studenti in base al cognome e al nome, verificheremo se i cognomi sono uguali, confrontandoli con i nomi; altrimenti confronta in base ai cognomi.

E la nostra espressione lambda sarà simile a questa.

(o1, o2) -> {
  if (o1.getLastName().equals(o2.getLastName())) {
    return o1.getFirstName().compareTo(o2.getFirstName());
  } else {
    return o1.getLastName().compareTo(o2.getLastName());
  }
});Code language: Java (java)

In alternativa, il Confronto supporta la composizione di più Comparator istanze insieme . Usando questo possiamo ordinare una raccolta con più campi.

students.sort(
  Comparator.comparing(Student::getLastName)
    .thenComparing(Student::getFirstName)
);Code language: Java (java)

Qui abbiamo usato Comparator#comparing() metodo factory per creare un comparatore basato sul cognome e utilizzato thenComparaing() – un altro metodo di fabbrica che confronta in base al nome. Entrambi questi comparatori saranno logicamente composti in un'unica istanza di Comparator.

Student(studentId=1, firstName=Tom, lastName=F, age=21)
Student(studentId=5, firstName=Nick, lastName=G, age=17)
Student(studentId=3, firstName=Jack, lastName=P, age=20)
Student(studentId=4, firstName=Jon, lastName=W, age=22)

Pertanto, il nostro output mostra che l'elenco delle istanze Student è ora ordinato in base a due campi diversi.

Ordina utilizzando l'ordinamento inverso (ordine decrescente)

Finora, abbiamo ordinato l'elenco degli studenti in base a vari campi in ordine crescente. In questa sezione parleremo dell'ordinamento dei campi in ordine inverso o decrescente.

Ordinamento inverso con espressione Lambda

Quando utilizziamo espressioni lambda per i comparatori, forniamo la nostra logica di confronto. Per ordinare i campi in ordine decrescente, dobbiamo semplicemente invertire l'espressione lambda.

Esempio di ordinamento decrescente del nome dello studente.

students.sort(
  (o1, o2) -> o2.getFirstName().compareTo(o1.getFirstName()));Code language: Java (java)

Qui stiamo confrontando il campo del nome della seconda istanza con quello della prima istanza.

Student(studentId=1, firstName=Tom, lastName=F, age=21)
Student(studentId=5, firstName=Nick, lastName=G, age=17)
Student(studentId=2, firstName=Karl, lastName=F, age=18)
Student(studentId=4, firstName=Jon, lastName=W, age=22)
Student(studentId=3, firstName=Jack, lastName=P, age=20)

Ecco perché otteniamo un output ordinato invertito.

Ordinamento inverso utilizzando Comparator.reverseOrder()

In alternativa, se stiamo usando Comparator Come metodi di fabbrica statici, possiamo usare un metodo statico di Comparator#reverseOrder() per istruire l'ordine di ordinamento inverso.

students.sort(Comparator.comparing(
  Student::getAge, 
  Comparator.reverseOrder()));Code language: Java (java)

Si noti che abbiamo fornito un parametro aggiuntivo per istruire l'ordinamento inverso.

Student(studentId=4, firstName=Jon, lastName=W, age=22)
Student(studentId=1, firstName=Tom, lastName=F, age=21)
Student(studentId=3, firstName=Jack, lastName=P, age=20)
Student(studentId=2, firstName=Karl, lastName=F, age=18)
Student(studentId=5, firstName=Nick, lastName=G, age=17)

Quindi nell'output, otteniamo lo studente più anziano in cima.

Ordina con comparatore e ordinamento misto

In aggiunta a questo, possiamo usare l'ordinamento inverso insieme alle composizioni del comparatore per creare espressioni di ordinamento ancora più complesse. Ad esempio, vogliamo ordinare le raccolte in ordine crescente di un campo e in ordine decrescente dell'altro .

students.sort(Comparator.comparing(
  Student::getLastName)
  .thenComparing(Student::getAge, Comparator.reverseOrder())
);
Code language: Java (java)

Stampiamo l'elenco dopo l'ordinamento.

Student(studentId=1, firstName=Tom, lastName=F, age=21)
Student(studentId=2, firstName=Karl, lastName=F, age=18)
Student(studentId=5, firstName=Nick, lastName=G, age=17)
Student(studentId=3, firstName=Jack, lastName=P, age=20)
Student(studentId=4, firstName=Jon, lastName=W, age=22)

Possiamo vedere, il nostro Confronto composizioni con ordinamento misto ha prodotto l'output previsto.

Riepilogo

Questa è stata una panoramica dell'utilizzo di Comparator basato su Java Lambda espressioni per ordinare le raccolte. Abbiamo iniziato con un esempio di ordinamento di una raccolta senza espressione lambda, in cui dovevamo fornire un'implementazione anonima in linea di Comparator interfaccia.

Successivamente abbiamo capito come l'utilizzo di espressioni Lambda per la stessa operazione di ordinamento renda il codice conciso. Abbiamo anche trattato l'utilizzo dei metodi di fabbrica statici dell'interfaccia di Comparator. I metodi factory creano un'istanza di Comparator in base ai campi e alle condizioni specificati.

Quindi abbiamo scritto alcune operazioni di confronto complesse come l'ordinamento in base a più campi di una raccolta. Infine, abbiamo accennato all'esecuzione dell'ordinamento inverso con le espressioni lambda e l'istanza del comparatore e abbiamo anche trattato l'implementazione di un ordinamento misto.

Per la fonte completa degli esempi qui utilizzati, visita il nostro Github Repository .


Etichetta Java