Otras recomendaciones de Java

LIBP-0023 (Libro de pautas)

Se describen otras recomendaciones a tener en cuenta al escribir código Java.

Pautas

TítuloCarácter
Siempre inicializar las superclasesObligatoria
Usar "Factorías" para crear objetosObligatoria
Asignar a Null las referencias que ya no se usarán másObligatoria
Incluir Cast en las condicionesObligatoria
Uso de las cadenas de caracteresObligatoria
Clases de uso de propósito generalObligatoria
Control sobre el cierre de conexionesObligatoria
Uso de Clone()Obligatoria
Uso de hashCode()Obligatoria
Uso de equals()Obligatoria
Uso de url, urn, acceso a ficherosObligatoria
Ordenación de listadosObligatoria
Uso del "pool" de conexionesObligatoria
Estructurar el código de forma generalRecomendada
Eliminar el código invariable de los buclesObligatoria
Eliminar los cálculos redundantesObligatoria
Manejo de los modificadores en las sentenciasObligatoria
Manejo de la instrucción WaitObligatoria
Otras recomendacionesRecomendada

Siempre inicializar las superclases

Si hay una clase dependiente de una superclase diferente de Object, la superclase debe de estar inicializada.

Usar "Factorías" para crear objetos

Siguiendo el patrón de diseño Factoría, diseñamos métodos para la creación pública de objetos. Con el uso de Factoría en lugar de la llamada al constructor conseguimos una mayor flexibilidad a la hora de crear nuevos objetos, además de una mejor separación entre la interfaz y la implementación.

Asignar a Null las referencias que ya no se usarán más

Especialmente interesante en el caso de los arrays, ya que activaremos el recolector de basura, liberando memoria sustancialmente.

Incluir Cast en las condiciones

Esto fuerza a considerar qué hacer si el objeto no es una instancia de la clase considerada en lugar de lanzar la excepción correspondiente.

Uso de las cadenas de caracteres

  • No es recomendable concatenar cadenas de caracteres mediante " + ", es más efectivo a niveles de rendimiento usar los métodos para ello como StringBuilder o StringBuffer.
  • No deben realizarse comparaciones de cadenas de caracteres mediante los operadores != ni ==. Se recomienda el uso del método equal.
  • No construir una cadena, el uso de la java.lang.String (String) es un gasto de memoria porque el objeto de su construcción será funcionalmente indistinguible de la cadena pasada como parámetro. Sólo tiene que utilizar el argumento de cadena directamente.
  • No haga un uso redundante de las cadenas de caracteres. Por ejemplo, la llamada String.toString() es justamente una operación redundante. Simplemente haga uso de String.
  • La creación de un objeto java.lang.String nuevo utilizando el constructor sin argumentos malgasta memoria porque el objeto así creado será funcionalmente indistinguible de la cadena vacía constante "". Java garantiza que las constantes idénticas de tipo cadena serán representadas por el mismo objeto String. Por lo tanto, sólo debe utilizar la cadena vacía constante directamente.
  • No crear literales de forma repetitiva, encapsularlos en cadenas reutilizables.
  • Use StringBuffer.length() para determinar el tamaño de StringBuffer mejor que usar using StringBuffer.toString().equals("") or StringBuffer.toString().length()
  • Realizar una estimacion correcta del tamañao de Stringbuffer, si no será necesario rediseñarlo en tiempo de ejecución con la consecuencia de la bajada de rendimiento.

Clases de uso de propósito general

Implementar los métodos equals(), hashCode(), toString(), y clone() especialmente para clases que van a tener un uso de propósito general.

Control sobre el cierre de conexiones

Hay que controlar que se cierran las conexiones cuando ha terminado la comunicación tras un acceso a base de datos, fichero, etc.

Uso de Clone()

Si se piensa que Clone() puede ser usado, entonces definirlo explícitamente y no dejar que se use el que se encuentra definido por defecto. El caso por defecto hace una copia ligera que podría no tener el nivel de profundidad de copiado que buscamos. A la hora de implementar el método debe considerarse que

  • Es necesario evitar que el método clone lance una excepción del tipo, CloneNotSupportedException.
  • El método sólo debe implementarse si la clase implementa la interfaz Cloneable con la excepción de un método final que sólo arroja CloneNotSupportedException.
  • No debe de retornar null, hay que vigilar la sobrescritura del método
  • Los constructores y métodos que reciben arrays deben clonar objetos y almacenar la copia. Esto evita que los futuros cambios del usuario afecten a la funcionalidad interior.

Uso de hashCode()

Normalmente todos los contenedores que agrupan o comparan objetos usando comparaciones de igualdad, utilizan los "hash codes" para determinar dicha igualdad. Se debe de asegurar que si una clase sobreesscribe el método hashCode() hace lo propio con el método equals().

Uso de equals()

A la hora de implementar el método debe considerarse que:

  • Se debe comprobar que no existan argumentos vacios.
  • Evitar llamadas en dos referencias de diferentes tipos de clase sin subclases comunes.
  • Evitar que la llamada siempre devuleva falso o cierto.
  • Comprobar las sobrescritura del método original para no introducir errores.

Uso de url, urn, acceso a ficheros

Hay que evitar introducir cadena de caracteres directamente en el código. Es recomendable utilizar las variables correspondientes para ello según cada lenguaje. Por ejemplo, en el lenguaje Java se recomienda el uso de pathSeparator.

Ordenación de listados

Es muy importante la forma en la que se muestra el contenido de las búsquedas y listados. Los listados que se presenten a los usuarios deben mostrar algún criterio de ordenación.

Uso del "pool" de conexiones

Es muy recomendable realizar las conexiones con la base de datos, tanto de lectura como de escritura mediante un "pool" de conexiones.

Estructurar el código de forma general

Estandarizar el desarrollo de forma jerárquica, estructurando las clases y componentes de forma estándar, definiendo los métodos de mayor importancia funcional previamente a los de menor importancia funcional.

Eliminar el código invariable de los bucles

Todo aquel código cuya ejecución produzca siempre el mismo resultado, es decir sea invariable, debe ser extraído del interior de los bucles.

Eliminar los cálculos redundantes

Eliminar cálculos redundantes, extrayendo las subexpresiones comunes.

Manejo de los modificadores en las sentencias

Se deben seguir las siguientes recomendaciones:

  • Se debe respetar el orden de los modificadores a la hora de definir los objetos Java. El orden debe ser el siguiente:
1. public
   2. protected
   3. private
   4. abstract
   5. static
   6. final
   7. transient
   8. volatile
   9. synchronized
  10. native
  11. strictfp
  • No declarar modficadores que no se utilicen.
  • No declarar el modificador final en los métodos si su clase se ha declarado como final.
  • Evitar modificadores redundantes.

Manejo de la instrucción Wait

La instrucción wait debe seguir las siguientes recomendaciones:

  • No realizar métodos que contengan una llamada a java.lang.Object.wait () que no esté en un bucle. Si el monitor se utiliza para varias condiciones, la condición de la persona que llama que pretende esperar podría no ser la que realmente ocurrió.
  • No realizar métodos que contengan llamadas a java.util.concurrent.wait() por el mismo motivo anterior.
  • No realizar métodos que contengan una llamada a java.lang.Object.wait () que no está protegida por control de flujo condicional. El código debe verificar que la condición que tiene la intención de esperar aún no está satisfecha antes de llamar a wait().
  • No crear métodos que llama Object.wait () sin que, obviamente, se mantenga un bloqueo en el objeto. Llamar a wait() sin un bloqueo que se traducirá en un IllegalMonitorStateException al ser lanzado.

Otras recomendaciones

En este apartado se incluyen las prácticas recomendadas para mejorar el mantenimiento, reutilización, etc. de los desarrollos realizados:

  • No introducir bloques vacios de código o código que no se utiliza.
  • Asegurar que las variables incrementadas dentro de los bucles son las correctas
  • Hacer uso de los mecanismos de herencia: cuantos más métodos se hereden, menos código se tendrá que escribir.
  • Evitar llamar a Object.notify() o Object.notifyAll() sin que, obviamente, se mantenga un bloqueo en el objeto.
  • Utilizar un máximo de tres niveles de herencia favoreciendo así la compresión del código y evitando excesiva complejidad en el mismo.
  • Evitar codigo cíclico.
  • Evite comparaciones que siempre devuelven el mismo resultado.
  • Evitar método con llamadas Thread.Sleep() con un bloqueo mantenido. Esto puede resultar en un rendimiento muy pobre y escalabilidad, o un estancamiento, ya que otros subprocesos pueden estar esperando para adquirir el bloqueo. Es una idea mucho mejor llamar a wait () en la cerradura, que libera el bloqueo y permite que otros hilos de ejecución.
  • Se recomienda el uso de Map en lugar de utilizar Hashtable.
  • Se recomienda el uso de java.util.Iterator en lugar de utiliar Enumeration.
  • Una operación en un objeto inmutable (String, BigDecimal o BigInteger) no va a cambiar el objeto en sí. El resultado de la operación es un nuevo objeto. Por lo tanto, ignorar el resultado de la operación es un error.
  • Evitar la búsqueda de null ante un instanceof. La palabra clave instanceof devuelve falso cuando se le da un argumento nulo.
  • Controlar la incializacion perezosa de los atributos.
  • Declarar public final serialversionUID para todo lo que pueda ser persistente.
  • Estudie reemplazar los vectores por el uso de ArrayList.
  • Evite crear instancias de un objeto con sólo llamadas al método getClass().
  • No utilizar las palabras "Enum" o "Assert" como identificadores.
  • Nunca realice llamadas a System.runFinalizersOnExit o Runtime.runFinalizersOnExit.