¿Te gustaría aprender Java desde cero?
Tenemos los cursos que necesitas.¡Haz clic aquí!

Este artículo presenta algunas de las mejores prácticas en la programación básica de Java que los programadores deben considerar implementar en sus actividades diarias de codificación. Ya que ayuda a los programadores de Java a escribir un buen código que se ajuste a las mejores prácticas. Aquí está la lista de las 10 mejores prácticas:

1. Uso de convenciones de nomenclatura

En primer lugar, antes de escribir cualquier código, debes especificar un conjunto de convenciones de nomenclatura para su proyecto Java, como cómo nombrar clases e interfaces, cómo nombrar métodos, cómo nombrar variables, cómo nombrar constantes, etc. Estas convenciones deben ser obedecido por todos los programadores de tu equipo. Un identificador (una clase, un método y una variable) debe tener las siguientes características: 

  • Autoexplicativo : un nombre debe revelar su intención para que todos puedan entender y cambiar el código fácilmente. Por ejemplo, los nombres d o str no revelan nada; sin embargo, los nombres daysToExpire o inputText revelan claramente su intención. Ten en cuenta que si un nombre requiere un comentario para describirse a sí mismo, entonces el nombre no se explica por sí mismo.
  • Distinciones significativas : si los nombres deben ser diferentes, también deberían significar algo diferente. Por ejemplo, los nombres a1 y a2 son distinciones sin sentido; y los nombres fuente y destino son distinciones significativas.  
  • Pronunciable : los nombres deben ser pronunciables tan naturalmente como el lenguaje hablado porque somos humanos, muy buenos con las palabras. Por ejemplo, ¿qué nombre puede pronunciar y recordar fácilmente: genStamp o generationTimestamp ?

Aquí hay algunas reglas generales de nombres:

  • Los nombres de clase e interfaz deben ser sustantivos, comenzando con una letra mayúscula. Por ejemplo: Estudiante , Automóvil , Rectángulo , Pintor , etc.  
  • Los nombres de las variables deben ser sustantivos, comenzando con una letra minúscula. Por ejemplo: número , contador , cumpleaños , género , etc.  
  • Los nombres de los métodos deben ser verbos, comenzando con una letra minúscula. Por ejemplo: ejecutar , iniciar , detener , ejecutar , etc.
  • Los nombres constantes deben tener todas las letras MAYÚSCULAS y las palabras están separadas por guiones bajos. Por ejemplo: MAX _ SIZE , MIN _ WIDTH , MIN _ HEIGHT , etc.  
  • Usando la notación camelCase para nombres. Por ejemplo: StudentManager , CarController , numberOfStudents , runAnalysis , etc.

Una buena referencia para las convenciones de nomenclatura es una publicación de Oracle: Convenciones de código Java . Puedes consultar este documento para crear tus propias convenciones de nomenclatura. Dicho esto, la nomenclatura es muy importante en la programación, ya que nombramos todo, desde clases a interfaces, métodos, variables y constantes, etc. Por lo tanto, no escribas código solo para satisfacer al compilador, escribe código para que sea legible y pueda ser entendido por humanos: primero es para ti, luego para tus compañeros de equipo y para otros tipos que terminan manteniendo tu proyecto. 

2. Ordenar miembros de la clase por ámbitos

La mejor práctica para organizar las variables miembro de una clase por sus ámbitos, desde los más restrictivos hasta los menos restrictivos. Eso significa que debemos ordenar los miembros por la visibilidad de los modificadores de acceso : privado, predeterminado (paquete), protegido y público. Y cada grupo separado por una línea en blanco. Por ejemplo, la siguiente declaración de miembros parece bastante desordenada:

public class StudentManager {
protected List listStudents;
public int numberOfStudents;
private String errorMessage;
float rowHeight;
float columnWidth;
protected String[] columnNames;
private int numberOfRows;
private int numberOfColumns;
public String title;
}

De acuerdo con esta práctica recomendada, la declaración de miembro anterior debe resolverse así:

public class StudentManager {
private String errorMessage;
private int numberOfColumns;
private int numberOfRows;


float columnWidth;

float rowHeight;

protected String[] columnNames;
protected List<Student> listStudents;

public int numberOfStudents;
public String title;
}

Y los miembros de cada grupo están ordenados por orden alfabético. Este estilo privado primero y público último nos ayuda a localizar rápidamente las variables miembro cuando la lista crece con el tiempo. 

3. Los miembros de la clase deben ser privados

Debemos minimizar la accesibilidad de los miembros de la clase (campos) lo más inaccesible posible. Eso significa que deberíamos usar el modificador de acceso más bajo posible (de ahí el privado modificador ) para proteger los campos. Esta práctica se recomienda para forzar la ocultación o encapsulación de información en el diseño de software.Considera la siguiente clase cuyos campos se hacen públicos:

public class Student {
public String name;
public int age;
}

El problema con este diseño pobre es que cualquiera puede cambiar los valores de los campos de manera inapropiada. Por ejemplo:

Student student = new Student();
student.name = "";
student.age = 2005;

Por supuesto, no queremos que el nombre esté vacío y que la edad no sea realista. Entonces, esta práctica nos anima a ocultar los campos y permitir que el código externo los cambie a través de métodos de establecimiento (o mutadores). Aquí hay un ejemplo de un mejor diseño:

public class Student {

private String name;
private int age;

public void setName(String name) {
if (name == null || name.equals("")) { throw new IllegalArgumentException("Name is invalid");
}

this.name = name;

}

public void setAge(int age) {
if (age < 1 || age > 100) {
throw new IllegalArgumentException("Age is invalid");
}
this.age = age;
}
}

Como puedes ver, el nombre y la edad de los campos se declaran privados, por lo que el código externo no puede cambiarlos directamente (ocultación de información). Y proporcionamos dos métodos setter setName () y setAge () que siempre verifican los argumentos válidos antes de actualizar los campos. Esto garantiza que los campos siempre obtengan los valores adecuados.

4. Uso de guiones bajos en literales numéricos

Esta pequeña actualización de Java 7 nos ayuda a escribir largos literales numéricos mucho más legibles. Considera la siguiente declaración:

int maxUploadSize = 20971520;
long accountBalance = 1000000000000L;
float pi = 3.141592653589F;

Y compara con este:

int maxUploadSize = 20_971_520;
long accountBalance = 1_000_000_000_000L;
float pi = 3.141_592_653_589F;

¿Cuál es más legible? Así que recuerda usar guiones bajos en literales numéricos para mejorar la legibilidad del código. 

5. Evita los bloques de captura vacíos

Es un mal hábito dejar los bloques catch vacíos, ya que cuando la excepción es atrapada por el bloque catch vacío, el programa falla en silencio, lo que dificulta la depuración. Considera el siguiente programa que calcula la suma de dos números a partir de argumentos de la línea de comandos:

public class Sum {
public static void main(String[] args) {
int a = 0;
int b = 0;

  try {
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]); 
} catch (NumberFormatException ex) {
} 

int sum = a + b;
 System.out.println("Sum = " + sum);
}
}

Ten en cuenta que el bloque catch está vacío. Si ejecutamos este programa con la siguiente línea de comando:

java Sum 123 456y

Fallará en silencio:

Sum = 123

Es porque el segundo argumento hace que se arroje una NumberFormatException , pero no hay código de manejo en el bloque catch, por lo que el programa continúa con un resultado incorrecto.Por lo tanto, la mejor práctica es evitar bloques de captura vacíos. En general, debemos hacer lo siguiente al detectar una excepción:

  • Informa al usuario sobre la excepción, por ejemplo, dile que vuelva a ingresar entradas o muestre un mensaje de error. Esto es muy recomendable.
  • Registra la excepción utilizando JDK Logging o Log4J.
  • Envuelve y vuelve a lanzar la excepción bajo una nueva excepción.

Dependiendo de la naturaleza del programa, el código para manejar la excepción puede variar. Pero la regla de oro nunca es «comer» una excepción por un bloque de captura vacío.Aquí hay una mejor versión del programa anterior:

public class Sum {
public static void main(String[] args) {
int a = 0;
int b = 0; 

try {
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]); 

} catch (NumberFormatException ex) {

System.out.println("One of the arguments are not number." +"Program exits.");

return;
} 

int sum = a + b;

  System.out.println("Sum = " + sum);
}
}

6. Usando StringBuilder o StringBuffer en lugar de String Concatenation

En Java, utilizamos el operador + para unir cadenas de esta manera:

public String createTitle(int gender, String name) {
String title = "Dear "; 

if (gender == 0)
{title += "Mr";
} else {
title += "Mrs";
} 
return title;
}

Esto está perfectamente bien ya que solo unos pocos objetos String están involucrados. Sin embargo, con el código que implica la concatenación de muchas cadenas, como la construcción de sentencias SQL complejas o la generación de texto HTML extenso, el operador + se vuelve ineficiente a medida que el compilador Java crea muchos objetos de cadena intermedios durante el proceso de concatenación.Por lo tanto, la mejor práctica recomienda usar StringBuilder o StringBuffer para reemplazar el operador + para concatenar muchos objetos String juntos a medida que modifican un String sin crear objetos String intermedios . StringBuilder no es seguro para subprocesos y StringBuffer es una versión segura para subprocesos. Por ejemplo, considera el siguiente fragmento de código que usa el operador + para generar una consulta SQL:

String sql = "Insert Into Users (name, email, pass, address)";
sql += " values ('" + user.getName();
sql += "', '" + user.getEmail();
sql += "', '" + user.getPass();
sql += "', '" + user.getAddress();
sql += "')";

Con StringBuilder , podemos reescribir el código anterior de esta manera:

StringBuilder sbSql
= new StringBuilder("Insert Into Users (name, email, pass, address)");
 sbSql.append(" values ('").append(user.getName());
sbSql.append("', '").append(user.getEmail());
sbSql.append("', '").append(user.getPass());
sbSql.append("', '").append(user.getAddress());
sbSql.append("')"); 
String sql = sbSql.toString();

7. Usando Enums o Constant Class en lugar de Constant Interface

Es una muy mala idea crear una interfaz que sea únicamente para declarar algunas constantes sin ningún método. Aquí hay una interfaz de este tipo:

public interface Color {
public static final int RED = 0xff0000;
public static final int BLACK = 0x000000;
public static final int WHITE = 0xffffff;}

Es porque el propósito de las interfaces es la herencia y el polimorfismo , no para cosas estáticas como esa. Entonces, la mejor práctica nos recomienda usar una enumeración en su lugar. Por ejemplo:

public enum Color {
BLACK, WHITE, RED
}

En caso de que el código de color sea importante, podemos actualizar la enumeración de esta manera:

public enum Color { 

BLACK(0x000000),
WHITE(0xffffff),
RED(0xff0000); 

private int code; 
Color(int code) {
this.code = code;
} 

public int getCode() {
return this.code;
}
}

En un proyecto complejo, podemos tener una clase dedicada a definir constantes para la aplicación. Por ejemplo:

public class AppConstants {
public static final String TITLE = "Application Name"; 

public static final int VERSION_MAJOR = 2;
public static final int VERSION_MINOR = 4;
 public static final int THREAD_POOL_SIZE = 10;
 public static final int MAX_DB_CONNECTIONS = 50;
 public static final String ERROR_DIALOG_TITLE = "Error";
public static final String WARNING_DIALOG_TITLE = "Warning";
public static final String INFO_DIALOG_TITLE = "Information";
}

Entonces, la regla general es: no uses interfaces para constantes, usa enumeraciones o clases dedicadas en su lugar. 

8. Evita la inicialización redundante (0-falso-nulo)

Es muy innecesario inicializar las variables miembro a los siguientes valores: 0 , falso y nulo . Debido a que estos valores son los valores de inicialización predeterminados de las variables miembro en Java. Por ejemplo, la siguiente inicialización en la declaración es innecesaria:

public class Person {
private String name = null;
private int age = 0;
private boolean isGenius = false;
}

Esto también es redundante:

public class Person {
private String name;
private int age;
private boolean;

 public Person() {
String name = null;
int age = 0;
boolean isGenius = false;
}
}

Por lo tanto, si conoces los valores de inicialización predeterminados de las variables miembro, evitará una inicialización explícita innecesaria. 

9. Uso de referencias de interfaz a colecciones

Al declarar objetos de colección, las referencias a los objetos deben ser lo más genéricas posible. Esto es para maximizar la flexibilidad y proteger el código de posibles cambios en la clase de implementaciones de recopilación subyacente. Eso significa que deberíamos declarar objetos de colección usando sus interfaces List , Set , Map , Queue y Deque. Por ejemplo, la siguiente clase muestra un mal uso de las referencias de colección:

public class CollectionsRef { 

private HashSet<Integer> numbers; 

public ArrayList<String> getList() { 

return new ArrayList<String>();
}
 public void setNumbers(HashSet<Integer> numbers) {
this.numbers = numbers;
}
}

Mira los tipos de referencia que son clases de implementación de colección: esto bloquea el código para que funcione solo con estas clases HashSet y ArrayList . ¿Qué sucede si queremos que el método getList () pueda devolver una LinkedList y el método setNumbers () pueda aceptar un TreeSet ? La clase anterior se puede mejorar reemplazando las referencias de clase por referencias de interfaz como esta:

public class CollectionsRef {

  private Set<Integer> numbers; 

public List<String> getList() {
// can return any kind of List
return new ArrayList<String>();
}
 public void setNumbers(Set<Integer> numbers) {
// can accept any kind of Set
this.numbers = numbers;
}
}

10. Evita usar bucles con índices

No uses un bucle for con una variable de índice (o contador) si puede reemplazarlo con el bucle for mejorado (desde Java 5) o forEach (desde Java 8). Se debe a que la variable de índice es propensa a errores, ya que podemos alterarla incidentalmente en el cuerpo del bucle o podemos comenzar el índice desde 1 en lugar de 0. Considera el siguiente ejemplo que itera sobre una matriz de cadenas:

String[] names = {"Alice", "Bob", "Carol", "David", "Eric", "Frank"}; 

for (int i = 0; i < names.length; i++) {
doSomething(names[i]);
}

Como puedes ver, la variable de índice i en este bucle for puede alterarse de manera incidental, lo que puede causar un resultado inesperado. Podemos evitar posibles problemas utilizando un bucle for mejorado como este:

for (String aName : names) {
doSomething(aName);
}

Esto no solo elimina posibles problemas, sino que también hace que el código sea más limpio y conciso. 

Te esperamos en los siguientes artículos en donde hablaremos más acerca de estos temas, los cuales hoy en día son de vital importancia en el mundo de la tecnología.

¿Te gustaría aprender Java desde cero?
Tenemos los cursos que necesitas.¡Haz clic aquí!

About Author

NGuerrero

0 0 votos
Article Rating
Suscribir
Notificar de
guest
2 Comments
La mas nueva
Más antiguo Más votada
Comentarios.
Ver todos los comentarios
jose Luis Cabrera
jose Luis Cabrera
2 Años Texto atrás

Realmente excelente.. gracias

2
0
¿Te gusta este articulo? por favor comentax