sábado, 20 de marzo de 2010

Ordenando listas de POJOs en Java por distintos criterios

Hoy un punto breve y simple para aquellos que siempre tienen dudas sobre como ordenar las colecciones que típicamente nos devuelven frameworks como Hibernate, JPA etc. Aunque muchas veces es mejor dejar que la BDD nos ordene directamente los registros en la consulta, a veces no es posible o por flexibilidad podemos desear hacerlo en el código.

Dicho esto, pasemos al código de ejemplo:

package test;

import java.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

public class App
{
  static class Item
  {
    private int codigo;
    private String nombre;

    public static Comparator COMPARADOR_POR_NOMBRE = new Comparator()
    {
      private Collator theC = Collator.getInstance();

      @Override
      public int compare(Object o1, Object o2)
      {
        Item item1 = (Item) o1;
        Item item2 = (Item) o2;
        return theC.compare(item1.getNombre(), item2.getNombre());
      }
    };

    public static Comparator COMPARADOR_POR_CODIGO = new Comparator()
    {

      @Override
      public int compare(Object o1, Object o2)
      {
        Item item1 = (Item) o1;
        Item item2 = (Item) o2;
        return item1.getCodigo() - item2.getCodigo();
      }
    };

    public Item(int codigo, String nombre)
    {
      this.codigo = codigo;
      this.nombre = nombre;
    }

    public int getCodigo()
    {
      return codigo;
    }

    public String getNombre()
    {
      return nombre;
    }

    @Override
    public String toString()
    {
      return this.codigo + ": " + this.nombre;
    }

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

    @Override
    public boolean equals(Object obj)
    {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (!(obj instanceof Item))
        return false;
      Item other = (Item) obj;
      if (codigo != other.codigo)
        return false;
      return true;
    }

  }

  public static void main(String[] args) throws InterruptedException
  {
    List listaDeItems = new LinkedList();
    listaDeItems.add(new Item(2, "Pedro"));
    listaDeItems.add(new Item(1, "Juan"));
    listaDeItems.add(new Item(3, "María"));
    listaDeItems.add(new Item(0, "Paco"));
    System.err.println("Lista tal cual\n-----------------");
    for (Item unItem : listaDeItems)
    {
      System.err.println(".- " + unItem);
    }
    Collections.sort(listaDeItems
                     ,Item.COMPARADOR_POR_NOMBRE);
    System.err.println("Lista ordenada por nombre\n-----------------");
    for (Item unItem : listaDeItems)
    {
      System.err.println(".- " + unItem);
    }
    Collections.sort(listaDeItems
                     ,Item.COMPARADOR_POR_CODIGO);
    System.err.println("Lista ordenada por codigo\n-----------------");
    for (Item unItem : listaDeItems)
    {
      System.err.println(".- " + unItem);
    }
  }
}

Y la respuesta al ejecutar la aplicación sería:

Lista tal cual
-----------------
.- 2: Pedro
.- 1: Juan
.- 3: María
.- 0: Paco
Lista ordenada por nombre
-----------------
.- 1: Juan
.- 3: María
.- 0: Paco
.- 2: Pedro
Lista ordenada por codigo
-----------------
.- 0: Paco
.- 1: Juan
.- 2: Pedro
.- 3: María

El código ya es suficientemente explicativo, y únicamente resaltar el cuidado que hay que tener al implementar los comparadores ya que han de ser coherentes con el método equals, que no hay que olvidar implementar al igual que el método hashCode. Así que si según equals, dos objetos son iguales, el comparador ha de devolver 0. Ojo que esto significa que si esos dos objetos los metemos en una estructura que no permita repetidos, como por ejemplo ordenándolos a través de un SortedSet ,no importa lo que valgan el resto de campos que no se usan en el equals/compare, el objeto anterior desaparecerá. En este caso como usamos una lista durante todo el proceso, podemos meter objetos “repetidos” que no desaparecerán.

¡Felices ordenaciones!

EJ
Happy Coding!

1 comentario:

  1. Hola, si tengo que ordenar por fecha, luego por codigo de local y luego codigo de producto..?? como seria el codigo.

    Gracias.

    ResponderEliminar