Antipatrones de diseño

Leyendo un poco sobre GRASP llegué a este artículo (viejo artículo) que más de una vez he leído. Esta vez logré identificar algunos de los antipatrones en experiencias propias. Dejo un fragmento del mismo.

Un antipatrón de diseño es un patrón de diseño que invariablemente conduce a una mala solución.

Antipatrones de desarrollo de software:

  • Productividad a toda costa: La empresa busca la productividad a costa de la calidad del software y de la calidad de vida de sus empleados, intenta homogeneizar los puestos de trabajo quitando en la medida de lo posible los permisos a los programadores para que no dañen los sistemas operativos, monitoriza a los equipos de trabajo y actúa cortando la visibilidad de ciertas páginas o las reuniones de programadores, al final se consigue que se vaya la gente de la empresa cuando la situación es insostenible, esto suele ocurrir en ciclos de uno o dos años.
  • Responsable ausente (absentee manager): Situación en la que el principal responsable o coordinador se ausenta o permanece en paradero desconocido o no localizable durante importantes períodos de tiempo.
  • Sr. Amigo de todos (Mr. Nice Guy): Se aplica al gestor que pretende convertirse en amigo de todos.
  • Estrellas nacientes (rising upstart): Se aplica a quienes, teniendo potencial, no son capaces de respetar la progresión profesional establecida, y pretenden sortear los plazos y requisitos de aprendizaje y madurez.
  • Arma definitiva (ultimate weapon): Individuos altamente competentes en los que la organización o sus compañeros confían tanto que se convierten en el canal por el que todo pasa.
  • Arquitecto a obrero (super builder): Creencia por la que se asigna a un buen diseñador de software al desarrollo de código pensando en que tardara mucho menos en teclearlo.

Antipatrones de gestión de proyectos:

  • Humo y espejos (smoke and mirrors): Mostrar cómo será una funcionalidad antes de que esté implementada.
  • Software inflado (software bloat): Permitir que las sucesivas versiones de un sistema exijan cada vez más recursos.

Antipatrones de diseño de software:

  • Botón mágico (magic pushbutton): Tender, desarrollando interfaces, a programar la lógica de negocio en los métodos de interacción, implementando los resultados de las acciones del usuario en términos no suficientemente abstractos.
  • Fábrica de combustible (gas factory): Diseñar de manera innecesariamente compleja.
  • Gran bola de lodo (big ball of mud): Construir un sistema sin estructura definida.
  • Interfaz inflada (interface bloat): Pretender que una interfaz sea tan potente que resulta extremadamente difícil de implementar.
  • Inversión de abstracción (abstraction inversion): No exponer las funcionalidades implementadas que los usuarios necesitan, forzando a que se reimplementen a más alto nivel.
  • Re-dependencia (re-coupling): Introducir dependencias innecesarias entre objetos.

Antipatrones de diseño orientado a objetos:

  • Acoplamiento secuencial (sequential coupling): Construir una clase que necesita que sus métodos se invoquen en un orden determinado.
  • BaseBean: Heredar funcionalidad de una clase utilidad en lugar de delegar en ella.
  • Fallo de clase vacía (empty subclass failure): Crear una clase que no supera el test de la subclase vacía, es decir, que se comporta de manera diferente cuando se invoca desde una subclase que no añade modificación alguna.
  • Objeto todopoderoso (god object): Concentrar demasiada funcionalidad en una única parte del diseño (clase).
  • Singletonitis: Abuso de la utilización del patrón singleton.
  • YAFL (yet another layer, y otra capa más): Añadir capas innecesarias a un programa, biblioteca o framework. Esta tendencia se extendió bastante después de que se publicase el primer libro sobrepatrones.

Antipatrones metodológicos:

  • Factor de improbabilidad (improbability factor): Asumir que es improbable que un error conocido cause verdaderos problemas.
  • Martillo de oro (golden hammer): Asumir que nuestra solución favorita es universalmente aplicable, haciendo bueno el refrán a un martillo, todo son clavos.
  • Optimización prematura (premature optimization): Realizar optimizaciones sin disponer de la información suficiente para hacerlo con garantías, sacrificando decisiones de diseño.
  • Programación de copiar y pegar (copy and paste programming): Programar copiando y modificando código existente en lugar de crear soluciones genéricas.
  • Programación por permutación (programming by permutation): Tratar de aproximarse a una solución modificando el código una y otra vez para ver si acaba por funcionar.
  • Reinventar la rueda (reinventing the wheel): Enfrentarse a las situaciones buscando soluciones desde cero, sin tener en cuenta otras que puedan existir ya para afrontar los mismos problemas.
  • Reinventar la rueda cuadrada (reinventing the square wheel): Crear una solución pobre cuando ya existe una buena.

Antipatrones de gestión de la configuración:

  • Infierno de dependencias (dependency hell):Escenario de problemas producidos por las versiones de otros productos que se necesitan para hacer funcionar un tercero.
    • Infierno DLL (DLL hell): Problemas con las versiones, disponibilidad o proliferación de DLLs (específico de Microsoft Windows)
    • Infierno JAR (JAR hell): Problemas con diferentes versiones o ubicaciones de ficheros JAR (Java), típicamente causados por la falta de comprensión del modelo de carga de clases.

Fuente: Antipatrón de diseño

Anuncios
Etiquetado , ,

Invocar un EJB3 desplegado en Weblogic desde un cliente JSE

Hace un tiempo tuve que hacer un cliente Java 1.6 que ejecute varios métodos de un EJB3 que se encontraba corriendo sobre un Weblogic 10.3. Los dos en máquinas diferentes.
Luego de leer un rato y obtener varios errores de clases no encontradas (propias de Weblogic) por mi cliente en tiempo de ejecución, llegué a la solución: hay que generar un jar especial llamado wlfullclient.jar que tiene todas las clases necesarias y copiarlo al cliente.

Los pasos a seguir para hacerlo son (desde una consola):

  • Ir al directorio $WEBLOGIC_HOME/server/lib
  • Ejecutar el siguiente comando: java -jar wljarbuilder.jar
  • Copiar el archivo wlfullclient.jar generado a los clientes
  • Agregar dicho jar al classpath de los clientes

Aclaración: $WEBLOGIC_HOME representa el directorio raíz de la instalación de Weblogic.

En el link que dejo también se explica como generar el jar en su versión para Java 1.5.

Fuente: Using the WebLogic JarBuilder Tool

Recomendaciones para desarrollar con JSF

Buscando recomendaciones para el desarrollo de aplicaciones con JSF, encontré varios blogs que hablan del tema y se enfocan en diferentes aspectos de la tecnología. Desde listas con recomendaciones hasta workarounds para los problemas comunes.

Recomendaciones generales

Estos son los puntos básicos para partir con un modelo ordenado a la hora de comenzar a desarrollar con esta tecnología.

Para obtener más información visitar los links de la fuente.

Fuente:

Etiquetado , , ,

Java SE 7 – Características y mejoras

La versión 7 de Java fué liberada hace un tiempo. En la página oficial de Oracle se publicaron las características y mejoras incluídas en esta nueva versión en “Java SE 7 Freatures and Enhancements”.

Algunas de las nuevas características (brevemente descritas) que presenta son (todos los fragmentos de código de los ejemplos se brindan en la publicación original):

-> Binarios literales

Los tipos enteros (byte, short, int y long) pueden ser expresados en forma de valores binarios utilizando el prefijo 0b o 0B:

// An 8-bit 'byte' value:
byte aByte = (byte)0b00100001;

// A 16-bit 'short' value:
short aShort = (short)0b1010000101000101;

// Some 32-bit 'int' values:
int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;
int anInt3 = 0B101; // The B can be upclares one or more resper or lower case.

// A 64-bit 'long' value. Note the "L" suffix:
long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;

-> String en Switch

Es posible utilizar String en bloques switch

public String getTypeOfDayWithSwitchStatement(String dayOfWeekArg) {
     String typeOfDay;
     switch (dayOfWeekArg) {
         case "Monday":
             typeOfDay = "Start of work week";
             break;
         case "Tuesday":
         case "Wednesday":
         case "Thursday":
             typeOfDay = "Midweek";
             break;
         case "Friday":
             typeOfDay = "End of work week";
             break;
         case "Saturday":
         case "Sunday":
             typeOfDay = "Weekend";
             break;
         default:
             throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
     }
     return typeOfDay;
}

-> La sentencia try-with-resources

Consiste en un try que declara uno o más recursos. Un recurso es un objeto que debe ser cerrado cuando la aplicación finalice su utilización. Esta sentencia asegura que todos los recursos utilizados serán cerrados al finalizar el bloque. Cualquier objeto que implemente la interfaz java.lang.AutoCloseable, que incluye todos aquellos que implementen java.io.Closeable, pueden ser utilizados como recursos.

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

En versiones anteriores de Java, para lograr lo mismo que en el fragmento anterior se debería realizar algo así:

static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    return br.readLine();
  } finally {
    if (br != null) br.close();
  }
}

-> Atrapando múltiples tipos de excepciones

Es posible atrapar distintos tipos de excepciones en un solo catch reduciendo el código duplicado.

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

En versiones anteriores de Java:

catch (IOException ex) {
     logger.log(ex);
     throw ex;
catch (SQLException ex) {
     logger.log(ex);
     throw ex;
}

-> Guión bajo en literales numéricos

Ahora es posible agregar la cantidad deseada de guiones bajos (_) entre los literales numéricos. Esto esta pensado para facilitar la
lectura del código.

long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 	3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;

La siguiente es una lista con los lugares en los cuales NO es válido aplicarlos:

  • Al comienzo o final de un número
  • Junto al punto decimal en un literal decimal
  • Antes del sufijo f o F
  • En posiciones donde se espera una cadena de dígitos

Se muestra a continuación una serie de ejemplos donde se utilizan de forma válida e inválida:

float pi1 = 3_.1415F;      // Invalid; cannot put underscores adjacent to a decimal point
float pi2 = 3._1415F;      // Invalid; cannot put underscores adjacent to a decimal point
long socialSecurityNumber1
  = 999_99_9999_L;         // Invalid; cannot put underscores prior to an L suffix

int x1 = _52;              // This is an identifier, not a numeric literal
int x2 = 5_2;              // OK (decimal literal)
int x3 = 52_;              // Invalid; cannot put underscores at the end of a literal
int x4 = 5_______2;        // OK (decimal literal)

int x5 = 0_x52;            // Invalid; cannot put underscores in the 0x radix prefix
int x6 = 0x_52;            // Invalid; cannot put underscores at the beginning of a number
int x7 = 0x5_2;            // OK (hexadecimal literal)
int x8 = 0x52_;            // Invalid; cannot put underscores at the end of a number

int x9 = 0_52;             // OK (octal literal)
int x10 = 05_2;            // OK (octal literal)
int x11 = 052_;            // Invalid; cannot put underscores at the end of a number

-> Inferencia de tipos en la creación de instancias de tipos genéricos

Ahora es posible instanciar un objeto que utilice tipos genéricos de la siguiente forma:

Map<String, List<String>> myMap = new HashMap<>();

En versiones anteriores de Java:

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

En el link comentado al comienzo del artículo se puede ver las lista completa de nuevas características y mejoras de esta nueva versión de Java, y
una descripción más detallada de cada una de ellas.

Etiquetado , , ,

Como escribir código inmantenible (garantiza un empleo de por vida)

El siguiente texto es un fragmento traducido de “How To Write Unmaintainable Code” publicado por Roedy Green. El texto es muy bueno y estoy seguro que a más de uno le traerá recuerdos.

Espero que lo disfruten.

Introducción

En el interés de crear oportunidades laborales en el campo del lenguaje de programación Java, estoy distribuyendo estos consejos de los maestros en escribir código que es tan difícil de mantener, que la gente que viene su reemplazo, tarda años en hacer los más simples cambios. Adicionalmente, si sigues estas reglas rigurosamente, te garantizarás toda una vida de trabajo, ya que nadie más que tú tendrá la esperanza de mantener el código. Entonces, si sigues todas las reglas, puede que ni tú puedas mantener el código!

No querrás excederte. Tu código no deberá verse inmantenible, sólo deberá serlo. De lo contrario existe el riesgo de que sea reescrito o refactorizado.

Principios generales

Para frustrar al programador encargado de realizar el mantenimiento, debes entender como piensa. Él tiene tu gigante programa. No tiene tiempo para leerlo todo, menos para entenderlo. Quiere encontrar rápidamente el lugar para hacer el cambio, hacerlo e irse, sin tener efectos secundarios.

Sólo puede observar un pequeño pedazo de tu programa a la vez. Tú quieres estar seguro de que nunca podrá obtener una visión global haciendo eso. Quieres que sea de lo más difícil la tarea de encontrar el código que está buscando. Pero más importante aún, quieres que sea de lo más incómodo para él ignorar cualquier cosa de manera segura.

Los programadores se dejan llevar por las convenciones. Cada tanto, rompiendo sutilmente una convención, lo estarás forzando a leer cada línea de tu código con una lupa.

Podrás tener la idea de que cada característica de un lenguaje de programación hace que el código sea inmantenible – esto se da, si se usa de forma incorrecta.

Nombres

“Cuando uso una palabra, significa sólo lo que yo quiero que signifique – ni más ni menos”

Mucha de la habilidad de escribir código inmantenible consiste en el arte de dar nombres a métodos y variables. No importan para el compilador. Lo que da gran liberad de utilizarlos para confundir a los programadores encargados de realizar el mantenimiento.

Nuevos usos de nombres para bebés

Compra un libro de nombres para bebés y nunca estarás perdido para nombrar una variable. Fred es un nombre grandioso, y fácil de tipear. Si estás buscando nombres de variables fáciles de tipear, prueba adsf o aoeu.

Nombre de variables de una sola letra

Si llamas a tus variables a, b, c, entonces será imposible buscarlas usando un simple editor de texto. Adicionalmente, nadie podrá adivinar para qué son.

Errores ortográficos creativos

En caso de tener que utilizar nombres de variables y funciones descriptivos, escríbelos mal. Al escribirlos mal en algunos casos y bien en otros (por ejemplo: setPuertaAbierta setPuetraCerrada) se está inutilizando la efectividad de grep o una IDE para realizar búsquedas. Funciona espléndidamente bien. Agrega un sabor internacional escribiendo descripcion o description.

Se abstracto

En la tarea de dar nombres a funciones y variables, haz uso excesivo de palabras abstractas como eso, todo, dato, manejar, cosa, hacer, rutina, realizar, y los dígitos. Por ejemplo: rutinaX48, realizarFuncionDeDatos, hacerlo, manejarCosa.

A.C.R.Ó.N.I.M.O.S

Usa acrónimos para mantener el código breve. Los verdaderos hombres nunca definen los acrónimos; ellos los entienden genéticamente.

La sustitución del tesauro

Para matar el aburrimiento, usa un tesauro para obtener un vocabulario alternativo al referirte a una acción, por ejemplo: mostrar, ver, presentar. Vagamente señala que existe una pequeña diferencia, donde no es así. Sin embargo, si existen dos funciones similares que tienen una diferencia crucial, siempre utiliza la misma palabra para describirlas (por ejemplo: imprimir para referirse a “escribir a un archivo”, “poner tinta en un papel” y “mostrar en pantalla”). Bajo ninguna circunstancia sucumbir ante las demandas de escribir un glosario con el propósito especial de aclarar la ambigüedad en el lenguaje utilizado. Hacerlo sería una violación del principio de diseño estructurado de ocultación de información.

Utiliza formas plurales de otros idiomas

Esperando, Klingon, califican como idiomas para este propósito. Para pseudo-esperando pluraloj, agrega oj al final. Estarás haciendo tu parte para la paz mundial.

CapitaliZaciÓn

Aleatoriamente capitaliza la primer letra de una sílaba en el medio de una palabra. Por ejemplo: calcularToTales()

Reutiliza nombres

Donde las reglas del lenguaje de programación lo permita, dale a clases, constructores, métodos, variables miembro, parámetros y variables locales los mismos nombres. Para obtener puntos extra, reutiliza nombres de variables locales dentro de bloques { }. El objetivo es obligar al programador encargado de realizar el mantenimiento a examinar cuidadosamente el contexto de cada aparición de dichos nombres. En particular, en Java, disfraza a métodos ordinarios como constructores.

Los invito a leer el texto completo, que está en ingles en el link que mencioné arriba.

Etiquetado , ,

Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java – Parte 3

En esta ocasión voy a mostrar como buscar un objeto en una lista. El procedimiento es simple y requiere conocer dos métodos de la clase java.util.Collections:

  • sort(List<T> list): Método que ya se analizó en la Parte 1
  • binarySearch(List<? extends Comparable<? super T>> list, T key): busca el objeto “key” en la lista indicada, retornando el índice del objeto en dicha lista. Para obtener más detalles ver javadoc.

Hay dos puntos importantes sobre el método binarySearch:

  • La lista sobre la que se realiza la búsqueda debe estar ordenada
  • Los objetos que contiene la lista deben ser mutuamente comparables

 Estos dos puntos se vieron en las publicaciones anteriores. Por lo cual no se van a explicar nuevamente.

Buscando una String en una List<String>

A continuación se muestra un ejemplo de intento de búsqueda en una List<String> que no se encuentra ordenada:

Buscar String en List sin ordenar

Buscar String en List sin ordenar

Como resultado se obtiene un número negativo en lugar del índice esperado, esto se debe a que la lista no se encuentra ordenada.

Vamos a agregar una línea de código al ejemplo anterior para ordenar la lista:

Buscar String en List ordenada

Buscar String en List ordenada

En este caso se obtiene el valor 0, lo cual es lógico, ya que al ordenarse la lista quedaría:

nombres {

  Alex → 0

  Jose → 1

  Max → 2

}

Buscar un Auto en una List<Auto>

Se dispone de la siguiente clase:

Clase Auto

Clase Auto

Un ejemplo de búsqueda de un Auto en una List<Auto> sería:

Buscar Auto en List

Buscar Auto en List

La búsqueda se realiza exitosamente gracias a la implementación de java.lang.Comparable  y la sobreescritura de equals en la clase utilizada, que en este caso es Auto. Dicha lista ordenada quedaría así:

autos {

  auto(ADF456,Peugeot,207)  → 0

  auto(JSF123′,Volkswagen,Power)  → 1

}

¿Por qué se ordenó de esa manera? Por la implementación que se le dió al método compareTo de la clase Auto.

¿Qué ocurre si el objeto que se está buscando no existe en la lista?

En ese caso se retornará un valor negativo correspondiente a : -punto de inserción  1. El punto de inserción es el punto de la lista en la que se debería incluir el objeto. Por ejemplo: si se intenta buscar el nombrePascualaen la lista de nombres, se obtendrá el siguiente resultado:

Buscar String inexistente en List

Buscar String inexistente en List

Vemos que el valor obtenido por binarySearch es -4.

Evidentemente el objetoPascualano existe en la lista de nombres, que ordenada quedaría:

nombres {

  Alex → 0

  Jose → 1

  Max → 2

}

Pero si existiese, se encontraría en la posición 3, dado el orden natural de sus elementos. Entonces, 3 es el punto de inserción del objeto.

Dijimos que si el objeto no existe se retorna -punto de insersión – 1, en este caso sería: -3 – 1 = -4.

Conclusiones

Haciendo referencia al método binarySearch se puede observar:

  • Retorna el índice del elemento buscado.
  • Retornará un valor mayor o igual a cero en caso de encontrar el objeto buscado en la colección.
  • El valor retornado será negativo cuando la lista no se encuentre ordenada o cuando el valor buscado no exista en la lista ordenada.

Fin de Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java – Parte 3”.

Etiquetado , , , ,

Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java – Parte 2

En esta ocasión voy a mostrar como realizar una clase cuyos objetos sean mutuamente comparables. Primero, se utilizará la interfaz java.lang.Comparable, que se implementará en la clase en cuestión. Luego, se creará una clase aparte que actuará como comparador e implementará java.util.Comparator.

Para los ejemplos realizados se utilizó:

Ordenando listas implementando java.lang.Comparable

Supongamos que creamos una clase llamada Persona como la siguiente:

Clase Persona

Clase Persona

Generamos una lista de Persona, e intentamos ordenarla mediante el método sort de la clase utilitaria java.util.Collections:

Error de compilación en TestPersonaOrdenamiento

Error de compilación en TestPersonaOrdenamiento

Vemos que el compilador nos informa un error como el siguiente:

Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<Persona>). The inferred type Persona is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>

Lo que ese error nos indica, básicamente, es que la clase Persona no puede ser utilizada por el método sort, debido a que no es un Comparable. Es decir, los objetos de la clase Persona no son mutuamente comparables, lo cual es un requerimiento para poder efectuar el ordenamiento.

En este ejemplo, siguiendo con el anterior, vamos a realizar el ordenamiento alfabéticamente, en base al nombre de la persona. Para lo cual modificamos la clase, haciendo que implemente la interfaz java.lang.Comparable:

Clase Persona implementando Comparable

Clase Persona implementando Comparable

Puntos a tener en cuenta:

  • La interfaz java.lang.Comparable hace uso de generics, lo que nos permite indicarle el tipo a utilizar, esto facilita la implementación del método compareTo, que en lugar de recibir un Object y tener que realizar el casteo dentro del mismo, recibe directamente un objeto del tipo esperado.
  • En la definición del método compareTo comparamos la referencia actual del objeto (this) con la enviada como argumento (o): …this.getNombre().compareTo(o.getNombre())…

Si intentamos ejecutar nuevamente el ejemplo anterior, imprimiendo los objetos Persona en la lista antes y después de realizar el ordenamiento, vemos:

TestPersonaOrdenamiento ordenando Persona por nombre

TestPersonaOrdenamiento ordenando Persona por nombre

El ordenamiento se realizó correctamente.

Ordenando listas implementando java.util.Comparator

¿Qué pasa si ahora quiero ordenar los objetos de tipo Persona por su atributo apellido?

Asumamos que estamos trabajando en un proyecto y no tenemos acceso al código fuente de la clase Persona y queremos ordenar sus objetos bajo algún concepto en particular, en este caso, por su apellido.

Lo que necesitamos en este caso es crear un comparador. Un comparador no es más que una clase que implementa la interfaz java.util.Comparator y define el método compare:

Clase PersonaSortByApellido

Clase PersonaSortByApellido

Creamos una clase llamada PersonaSortByApellido, y la convertimos en un java.util.Comparator especificando que compare tenga en cuenta el apellido del objeto Persona al momento de realizar la comparación.

Puntos a tener en cuenta:

  • La interfaz java.util.Comparator también hace uso de generics, brindando los beneficios nombrados anteriormente.
  • La comparación se realiza entre dos objetos, ambos son enviados como argumento al método sort.

Para indicar que queremos ordenar los objetos utilizando este comparador, debemos utilizar la sobrecarga del método sort que recibe como segundo argumento un java.util.Comparator. Si hacemos este cambio en el ejemplo anterior el resultado será:

TestPersonaOrdenamiento utilizando un Comparator

TestPersonaOrdenamiento utilizando un Comparator

Observamos que en este caso el ordenamiento se realizó según lo indicado en el comparador PersonaSortByApellido, es decir, por apellido.

Fin de Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java Parte 2”.

Etiquetado , , , , , , , ,

Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java – Parte 1

Buscar un elemento en una colección o array es una tarea muy frecuente, al igual que ordenar los elementos que una colección o array contiene. La API de Java brinda una serie de clases, interfaces y métodos que se encargan de ello.

Para todos los ejemplos de esta primer parte se utilizará Sun (Oracle) JDK 1.6.0_25 64-Bit (http://www.oracle.com/technetwork/java/javaee/downloads/java-ee-6u2-wjdk-6u25-366881.html).

 Ordenando listas utilizando el orden natural de sus elementos

 Supongamos que tenemos una lista de nombres:

import java.util.List;

import java.util.ArrayList;

List<String> nombres = new ArrayList<String>();

nombres.add(“Matt”);

nombres.add(“Nick”);

nombres.add(“Alex”);

nombres.add(“Jamie”);

Ahora, posiblemente vayamos a presentar esta lista en pantalla, para que el usuario seleccione un elemento de ella. Este componente que se presenta en pantalla, sea una página web, una aplicación de escritorio, va a ser mucho más amigable si presenta la información de forma ordenada. En este caso, estamos tratando con nombres, y lo más lógico sería ordenarlos alfabéticamente.

Para ordenar una lista, es necesario conocer la clase utilitaria java.utils.Collections, la cual contiene un método estático llamado sort, sus versiones son (descripción extraída del javadoc: http://download.oracle.com/javase/6/docs/api/java/util/Collections.html):

  • void sort(List<T> list): Ordena los elementos de la lista de acuerdo al orden natural de sus elementos.
  • void sort(List<T>, Comparator<? super T> c): Ordena los elementos de la lista de acuerdo al Comparator indicado.

 El orden natural de los elementos

 El orden natural de los elementos dependerá del tipo de los elementos. Por ejemplo, para el caso de los String, el orden natural es el alfabético, para el caso de los números, numérico.

Ahora, ¿qué pasa para el caso de una clase propia?, es decir, supongamos que tengo una clase llamada Persona, ¿cuál es el su orden? Para este caso debemos indicar un comparador, que determinará cual es el concepto bajo el cual se compararán y ordenarán objetos de tipo Persona.

Definiendo un comparador

 Un comparador puede ser definido de dos formas:

Para los dos casos, ya sea definiendo compareTo o compare, su funcionamiento es el siguiente:

Comparando A y B el resultado del método, según los casos que se listan será:

  • Si A > B: número positivo
  • Si A < B: número negativo
  • Si A == B: 0

 Utilizando compareTo:

  • A: this
  • B: Argumento del método

 Utilizando compare:

  • A: Primer argumento
  • B: Segundo argumento

Volviendo al ejemplo de la lista de nombres, para realizar el ordenamiento deberíamos escribir:

import java.lang.Collections;

Collections.sort(nombres);

Esto ordenará la lista a la que referencia la variable nombres alfabéticamente.

Así termina la primer parte de Búsqueda y ordenamiento en colecciones y arrays sin reinventar la rueda utilizando Java”.

Etiquetado , , , , , , , ,