sort java string sorting java-8 comparator

sort object list java



Java 8 comparator nullFirst naturalOrder confuso (3)

El comparador de "orden natural", que es lo que obtiene cuando utiliza la comparing con un solo parámetro, no maneja nulos. (No estoy seguro de dónde surgió la idea de que sí.) El "orden natural" de una clase Comparable se define mediante el compareTo() , que se utiliza así:

obj1.compareTo(obj2)

Obviamente, esto no funcionará si obj1 es nulo; para String , también lanzará una excepción de que obj2 es nulo.

El método naturalOrder() devuelve un Comparator que compara dos objetos. El javadoc dice explícitamente que este comparador arroja NullPointerException al comparar null.

El método nullsFirst() (y nullsLast() manera similar) básicamente transforma un Comparator en un nuevo Comparator . Pones un comparador que puede arrojar una excepción si intenta comparar nulo, y arroja un nuevo comparador que funciona de la misma manera, excepto que permite argumentos nulos. Es por eso que necesita un parámetro para nullsFirst ya que crea un nuevo comparador sobre un comparador existente y le dice cuál es el comparador existente.

Entonces, ¿por qué no te da el orden natural si dejas fuera el parámetro? Porque ellos no lo definieron de esa manera. nullsFirst se define en javadoc para tomar un parámetro:

static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)

Creo que si los diseñadores quisieran, podrían haber agregado una sobrecarga que no requiere parámetros:

static <T> Comparator<T> nullsFirst() // note: not legal

eso sería lo mismo que usar nullsFirst(naturalOrder()) . Pero no lo hicieron, así que no puedes usarlo así.

esto puede ser una pregunta simple, pero me gustaría entenderlo claramente ...

Tengo un código como este:

public final class Persona { private final int id; private final String name public Persona(final int id,final String name) { this.id = id; this.name = name; } public int getId(){return id;} public String getName(){return name;} @Override public String toString(){return "Persona{" + "id=" + id + ", name=" + name+''}'';} }

Y estoy probando este código:

import static java.util.Comparator.*; private void nullsFirstTesting() { final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder())); final List<Persona>persons = Arrays.asList(new Persona(1,"Cristian"),new Persona(2,"Guadalupe"),new Persona(3,"Cristina"),new Persona(4,"Chinga"),new Persona(5,null)); persons .stream() .sorted(comparator) .forEach(System.out::println); }

Esto muestra los siguientes resultados:

Persona{id=5, name=null} Persona{id=4, name=Chinga} Persona{id=1, name=Cristian} Persona{id=3, name=Cristina} Persona{id=2, name=Guadalupe}

Estos resultados están bien para mí, pero tengo un problema para entenderlo.

Cuando ignoro el new Persona(5,null) y paso el comparador:

final Comparator<Persona>comparator = comparing(Persona::getName);

Funciona a las mil maravillas. Mi clasificación es por natural order of name property . El problema surge cuando agrego el objeto con name=null , solo pensé que necesitaría mi comparador de esta manera.

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst());

Mi pensamiento era erróneo : "OK, cuando el nombre no es nulo, están ordenados en natural order of name , al igual que el comparador anterior, y si son null serán los primeros, pero mis nombres no nulos aún se ordenarán en orden natural ".

Pero el código correcto es este:

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));

No entiendo el parámetro nullsFirst . Solo pensé que el natural order of name explícitamente [predeterminado] incluso manejaría valores null .

Pero los documentos dicen:

Devuelve un comparador null-friendly que considera que null es menor que non-null. Cuando ambos son null , se consideran iguales. Si ambos son no nulos, el Comparator especificado se usa para determinar el orden. Si el comparador especificado es null , el comparador devuelto considera que todos los valores no nulos son iguales.

Esta línea: "Si ambos no son nulos, el Comparator especificado se usa para determinar el orden".

Estoy confundido sobre cuándo y cómo se debe establecer explícitamente el orden natural o cuándo se deducen.


Tengo una lista de Empleado con Estudiante con nombre e id.

import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Comparator; public class TestClass { public static void main(String[] args) { Student s1 = new Student("1","Nikhil"); Student s2 = new Student("1","*"); Student s3 = new Student("1",null); Student s11 = new Student("2","Nikhil"); Student s12 = new Student("2","*"); Student s13 = new Student("2",null); List<Student> list = new ArrayList<Student>(); list.add(s1); list.add(s2); list.add(s3); list.add(s11); list.add(s12); list.add(s13); list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder()))); for (Iterator iterator = list.iterator(); iterator.hasNext();) { Student student = (Student) iterator.next(); System.out.println(student); } } }

Produce salida como

Student [name=*, id=1] Student [name=*, id=2] Student [name=Nikhil, id=1] Student [name=Nikhil, id=2] Student [name=null, id=1] Student [name=null, id=2]


Tratar:

final Comparator<Persona> comparator = comparing(Persona::getName, nullsFirst(naturalOrder()));