12 de las mejores prácticas en Java
1.- Evitar la creación innecesaria de objetos, Lazy Initialitation
La creación de objetos en Java es una de las operaciones mas costosas en términos de uso de memoria e impacto en el performance. Esto es evitable creando o inicializando objetos solo en el momento en que serán requeridos en el código.
- public class Paises {
- //se inicializa solo cuando es requerido
- if(null == paises) {
- }
- return paises;
- }
- }
2.- Nunca hacer variables de instancia públicas
Hacer una clase publica se puede ocasionar problemas en un programa. Por ejemplo si tienes una clase MiCalendario. Esta clase contiene un arreglo de cadenas diasDeLaSemana. Pero es una arreglo público y este puede ser accedido por cualquiera. Tu asumes que este arreglo contiene siempre los 7 nombres de los días de la semana. Alguien por error puede cambiar el valor e insertar un error!
- public class MiCalendario {
- {"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"};
- //mas código
- }
La mejor práctica es como mucho de ustedes saben, es siempre definir estas variables como privadas y crear los métodos accesores, “setters“ y “getters”
- {"Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Sabado", "Domingo"};
- return diasDeLaSemana;
- }
Pero escribir los métodos accesores no resuelve el problema del todo. El arreglo sigue siendo accesible. La mejor forma de hacerlo inmodificable es devolviendo un arreglo clonado en lugar del arreglo mismo. Esto se logra modificando el método get de la siguiente forma.
- return diasDeLaSemana.clone();
- }
3.- Tratar siempre de minimizar la Mutabilidad de las clases
Hacer una clase inmutable es hacerla inmodificable. La información de la clase se preservara durante el tiempo de vida de la clase. Las clases inmutables son simples y fáciles de manejar. Son “thread safe”. Normalmente son los bloques para formar otros objetos mas grandes.
No obstante, crear objetos inmutables pueden golpear significativamente el rendimiento de una aplicación. Así que elije cuidadosamente si quieres que una clase sea o no inmutable. Trata siempre de tener clases pequeñas con el menor número de clases inmutables.
Para hacer una clase inmutable puedes definir sus constructor de forma privada y luego crear un método estático para inicializar al objeto y devolverlo.
- public class Empleado {
- // constructor private default
- this. primerNombre = primerNombre;
- this. segundoNombre = segundoNombre;
- }
- return new Empleado (primerNombre, segundoNombre);
- }
- }
4.- Trata de usar mas las Interfaces sobre las Clases Abstractas
No es posible la herencia múltiple en Java, pero definitivamente puedes implementar múltiples interfaces. Esto hace que cambiar la implementación de una clase existente sea fácil y que puedas implementar una o mas interfaces en lugar de cambiar la jerarquía completa de clases.
Pero si tu estás cien por ciento seguro de que métodos de una interface tendrás, entonces solo implementa esa interfaz. Es bastante difícil agregar un nuevo método en una interfaz existente sin alterar todo el código que se está implementando. Por el contrario un nuevo método puede ser fácilmente agregado en una clase abstracta sin alterar la funcionalidad existente.
5.- Limita siempre el alcance de una variable local
Las variables locales son grandiosas. Pero algunas veces pueden insertar mas bugs durante el copiado y pegado de código viejo. Minimizar el alcance de una variable local hace que el código sea mas legible, menos propenso a errores y mas mantenible.
Por lo tanto, debemos declarar variables justo antes de ser usadas.
Procura inicializar una variable desde su declaración. Si eso no es posible asígnale el valor nulo.
6- Trata de usar librerías estándar en lugar de hacer las tuyas desde cero.
Escribir código es divertido. Pero no reinventes la rueda. Es bastante recomendable usar librerías estándar que ya han sido probadas, debugeadas y usadas por otros. Esto no solo mejora la eficiencia de un programador sino que redice las posibilidades de tener errores en el código. Además, usar una librería estándar hace al código mas legible y mantenible.
Por ejemplo Google tiene liberada la nueva librería Google Collections que puede ser usada para agregar mas funcionalidad a tu código.
7.- Siempre que sea posible trata de usar tipos primitivos en lugar de las clases Wrapper
Las clases Wrapper son buenas, pero también son lentas. Los tipos primitivos son como clases, sin embargo las clases wrapper almacenan la información completa acerca de una clase.
Algunas veces un programador puede agregar un error en el código usando una wrapper por un descuido. Por ejemplo:
- int x = 10;
- int y = 10;
El primer System.out.println imprimirá true mientras que el segundo imprimirá false. El problema cuando comparas dos clases wrapper es que no se puede usar el operador ==, por que en realidad se están comparando referencias y no sus valores actuales.
Además si estás usando una clase wrapper no debes olvidar inicializarla. Porque el valor por default de las variables wrapper es null.
- //mas código
- if(flag == true) {
- } else {
- }
El código lanzará un NullPointerException cuando se trate de comparar con true y el valor sea nulo si en el código intermedio no fue inicializada.
8.- Usa los Strings con mucho cuidado.
Usa siempre las cadenas con mucho cuidado en tu código. Una simple concatenación de cadenas puede reducir el rendimiento de tu programa. Por ejemplo si queremos concatenar cadenas usando el operador “+” en un ciclo for entonces todo el tiempo se estará creando un objeto String. Esto afecta tanto a la memoria como al rendimiento.
Además en lugar de que instancies una objeto String no uses su constructor, sino que debes instanciarlo directamente. Por ejemplo:
- //instanciación lenta
- //instanciación rápida
9.- Siempre regresa colecciones vacías en lugar de nulas
No importa que tu método regrese una colección o un arreglo, siempre asegúrate de que cuando sea necesario se regrese vacío y no nulo, en aquellos casos en los que no contendrá elementos porque la lógica de tu programa lo requiera. Esto te ahorrará un montón de tiempo cuando hagas pruebas para valores nulos.
10.- El copiado defensivo es salvador
El copiado defensivo hace que los objetos creados estén libres de la mutación. Por ejemplo en el código siguiente tenemos definida la clase Estudiante la cual a su vez tiene una variable con la fecha de nacimiento que es inicializada cuando el objeto es construido.
- public class Estudiante {
- public Estudiante(fechaNacimiento) {
- this. fechaNacimiento = fechaNacimiento;
- }
- return this.fechaNacimiento;
- }
- }
Ahora podríamos tener el siguiente código que use al objeto Estudiante.
- Estudiante estudiante = new Student(fechaNacimiento);
- fechaNacimiento.setYear(2019);
- }
En el código siguiente creamos tan solo al objeto Estudiante con algunas fechas de nacimiento por default. Pero entonces cambiamos el valor de el año de nacimiento. Después imprimimos el año de nacimiento, este año fue cambiado por 2019!
Para evitar estos casos, se puede utilizar el mecanismo defensivo copias. Cambie el constructor de la clase del estudiante a lo siguiente.
- public Estudiante(fechaNacimiento) {
- }
Esto para asegurarnos de tener otra copia de la fecha de nacimiento que usamos en clase Estudiante.
11.- Nunca dejes salir una excepción de un bloque finally
12.- Nunca lances "Exception" directamente.