Errores comunes en Java
NullPointerException
El error más común en Java.
Problema
String texto = null;int longitud = texto.length(); // ❌ NullPointerExceptionSoluciones
1. Validar null:
if (texto != null) { int longitud = texto.length();}2. Usar Optional:
Optional<String> textoOpt = Optional.ofNullable(texto);int longitud = textoOpt.map(String::length).orElse(0);3. Objects.requireNonNull:
public void procesar(String texto) { Objects.requireNonNull(texto, "texto no puede ser null"); // Usar texto con seguridad}Comparar Strings con ==
Problema
String a = new String("Hola");String b = new String("Hola");
if (a == b) { // ❌ false (compara referencias) System.out.println("Iguales");}Solución
if (a.equals(b)) { // ✅ true (compara contenido) System.out.println("Iguales");}No cerrar recursos
Problema
FileReader fr = new FileReader("archivo.txt");// Si hay excepción, fr nunca se cierrafr.read();fr.close();Solución: try-with-resources
try (FileReader fr = new FileReader("archivo.txt")) { fr.read();} // Se cierra automáticamenteModificar colecciones durante iteración
Problema
List<String> lista = new ArrayList<>(List.of("a", "b", "c"));
for (String elemento : lista) { if (elemento.equals("b")) { lista.remove(elemento); // ❌ ConcurrentModificationException }}Soluciones
1. Iterator:
Iterator<String> it = lista.iterator();while (it.hasNext()) { if (it.next().equals("b")) { it.remove(); // ✅ Correcto }}2. removeIf (Java 8+):
lista.removeIf(elemento -> elemento.equals("b"));3. Crear nueva lista:
List<String> nueva = lista.stream() .filter(e -> !e.equals("b")) .collect(Collectors.toList());Concatenar Strings en bucles
Problema
String resultado = "";for (int i = 0; i < 1000; i++) { resultado += i; // ❌ Muy ineficiente}Cada += crea un nuevo String.
Solución: StringBuilder
StringBuilder sb = new StringBuilder();for (int i = 0; i < 1000; i++) { sb.append(i); // ✅ Eficiente}String resultado = sb.toString();Ignorar excepciones
Problema
try { // código que puede fallar} catch (Exception e) { // ❌ Tragar la excepción}Solución
try { // código} catch (Exception e) { logger.error("Error procesando datos", e); // O relanzar: throw new RuntimeException(e);}Usar tipos raw
Problema
List lista = new ArrayList(); // ❌ Sin tipo genéricolista.add("texto");lista.add(123);String texto = (String) lista.get(1); // ❌ ClassCastExceptionSolución
List<String> lista = new ArrayList<>(); // ✅ Con genéricoslista.add("texto");// lista.add(123); // Error de compilaciónOlvidar break en switch
Problema
int dia = 1;switch (dia) { case 1: System.out.println("Lunes"); // ❌ Sin break, continúa al siguiente caso case 2: System.out.println("Martes"); break;}// Imprime: Lunes\nMartesSolución
switch (dia) { case 1: System.out.println("Lunes"); break; // ✅ case 2: System.out.println("Martes"); break;}O usa switch expressions (Java 14+):
String nombre = switch (dia) { case 1 -> "Lunes"; // No necesita break case 2 -> "Martes"; default -> "Otro";};Autoboxing en bucles
Problema
// ❌ Crea objetos Integer innecesariamenteInteger suma = 0;for (int i = 0; i < 1000; i++) { suma += i; // Autoboxing/unboxing en cada iteración}Solución
// ✅ Usa tipos primitivosint suma = 0;for (int i = 0; i < 1000; i++) { suma += i;}Double para dinero
Problema
double precio = 0.1;double total = precio * 10;System.out.println(total); // 0.9999999999999999 ❌Solución: BigDecimal
BigDecimal precio = new BigDecimal("0.1");BigDecimal total = precio.multiply(new BigDecimal("10"));System.out.println(total); // 1.0 ✅No sobrescribir equals y hashCode
Problema
class Persona { String nombre; int edad;}
Persona p1 = new Persona("Juan", 25);Persona p2 = new Persona("Juan", 25);
System.out.println(p1.equals(p2)); // false ❌Solución
@Overridepublic boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof Persona)) return false; Persona otra = (Persona) obj; return edad == otra.edad && Objects.equals(nombre, otra.nombre);}
@Overridepublic int hashCode() { return Objects.hash(nombre, edad);}O usa records (Java 14+):
record Persona(String nombre, int edad) { }// equals, hashCode, toString generados automáticamenteNo usar interfaces
Problema
// ❌ Acoplamiento fuerteArrayList<String> lista = new ArrayList<>();Solución
// ✅ Programa contra la interfazList<String> lista = new ArrayList<>();Permite cambiar la implementación fácilmente:
List<String> lista = new LinkedList<>(); // Cambio sin afectar el restoStatic mutable state
Problema
public class Contador { public static int contador = 0; // ❌ Estado compartido mutable
public static void incrementar() { contador++; // No thread-safe }}Solución
public class Contador { private final AtomicInteger contador = new AtomicInteger(0);
public void incrementar() { contador.incrementAndGet(); // Thread-safe }
public int getContador() { return contador.get(); }}Buenas prácticas para evitar errores
- Usa Optional para valores que pueden ser null
- Valida parámetros al inicio de métodos
- Cierra recursos con try-with-resources
- Usa tipos genéricos siempre
- Evita estado mutable compartido
- Escribe tests unitarios
Próximo paso
Aprende principios de código limpio: Clean Code →