Skip to main content

Enums, String, StringBuffer y StringBuilder

¿Qué es un enum?

Un enum (abreviatura de enumeration) es un tipo especial de clase en Java que representa un conjunto fijo de constantes con nombre. Es ideal para modelar estados, categorías, roles o valores finitos e inmutables.

Por ejemplo: ACTIVE, INACTIVE, SUSPENDED son posibles estados de un usuario.

Ventajas:

  • Legibilidad del código.
  • Seguridad de tipo (no se permiten valores inválidos).
  • Fácil de mantener y extender.
UserStatus.java
public enum UserStatus {
ACTIVE,
INACTIVE,
SUSPENDED,
DELETED
}

UserStatus status = UserStatus.ACTIVE;

¿Por qué usar enum en vez de String o enteros?

AlternativaProblemas comunes
Cadenas (String)Errores de tipeo, valores inválidos, difícil mantenimiento
Números (int)Poco expresivos, sin validación, no indican claramente el valor
enumSeguro, legible, validado en tiempo de compilación

Características de los enum en Java

  1. Son clases especiales: Puedes agregar atributos, constructores, métodos.

  2. Tienen métodos útiles por defecto:

    UserStatus.ACTIVE.name();      // "ACTIVE"
    UserStatus.ACTIVE.ordinal(); // 0 (posición)
    UserStatus.valueOf("SUSPENDED"); // UserStatus.SUSPENDED

Ejemplo con atributos y métodos

Definición de un enum con atributos y métodos:

Priority.java
public enum Priority {
HIGH("🔴 Urgente"),
MEDIUM("🟡 Normal"),
LOW("🟢 Baja");

private final String label;

Priority(String label) {
this.label = label;
}

public String getLabel() {
return label;
}
}

Forma de uso:

Priority priority = Priority.HIGH;
System.out.println(priority.getLabel()); // "🔴 Urgente"

Llevemos el ejemplo un poco más allá usando un switch-case:

public String getMessageForStatus(UserStatus status) {
switch (status) {
case ACTIVE: return "Welcome!";
case SUSPENDED: return "Your account is suspended.";
case DELETED: return "User no longer exists.";
default: return "Unknown status.";
}
}

Buenas prácticas para los enums en Java

RecomendaciónEjemplo o razón
Usar nombres en MAYÚSCULASPENDING, APPROVED, REJECTED
Evitar asociar valores mágicosUsar enum en lugar de int con significado oculto
Añadir métodos cuando sea útilgetLabel(), getColorCode()
Usar switch para lógica contextualMensajes por estado, iconos, acciones
No usar enum para datos que cambianEj. categorías de producto si son configurables

¿Qué es String en Java?

String es una clase inmutable: cada vez que modificas una cadena, se crea una nueva instancia. Es útil para textos estáticos o de baja modificación.

String s = "Hello";
s = s + " World"; // Crea un nuevo objeto internamente

En Java, String es una clase (no un tipo primitivo) que representa una secuencia de caracteres Unicode. Es ampliamente usada para manejar textos, nombres, mensajes, rutas, comandos, entre otros.

¿Por qué es importante?

  • Todas las interacciones con el usuario y el sistema usan texto: nombres, contraseñas, correos, estados, etc.
  • Muchos errores en software ocurren por manipulación incorrecta de texto (ej. concatenación o validación).

Características clave

CaracterísticaExplicación
InmutableUna vez creado, su valor no puede cambiar. Toda modificación crea un nuevo objeto.
Optimizado internamenteUsa un String pool para evitar duplicados y ahorrar memoria.
Soporta UnicodeCompatible con múltiples idiomas y emojis.
Extremadamente usadoEstá presente en la mayoría de clases estándar, bases de datos, APIs, etc.

¿Por qué es inmutable?

Internamente, un String es final, y sus datos están protegidos. Esta inmutabilidad permite:

  • Seguridad en estructuras concurrentes.
  • Uso seguro como clave en HashMap.
  • Eficiencia en el string pool (evita crear múltiples copias).

Métodos comunes de la clase String

MétodoEjemplo de usoResultado
length()"Hola".length()4
charAt(i)"Hola".charAt(1)'o'
toUpperCase()"hola".toUpperCase()"HOLA"
trim()" hola ".trim()"hola"
equals("texto")"Java".equals("java")false
equalsIgnoreCase()"Java".equalsIgnoreCase("java")true
substring(1, 3)"Hola".substring(1,3)"ol"
split(" ")"uno dos tres".split(" ")["uno", "dos", "tres"]
contains("la")"Hola".contains("la")true

Errores comunes al usar String

ErrorMejor práctica
Comparar con ==Usar .equals()
Concatenar en bucles grandesUsar StringBuffer o StringBuilder
Olvidar trim() en inputSiempre limpiar entrada del usuario
Concatenar muchos + encadenadosUsar .concat() o builder

Mini ejemplo

StringExample.java
public class StringExample {
public static void main(String[] args) {
String fullName = " Ana María ";
System.out.println("Original: '" + fullName + "'");
fullName = fullName.trim().toUpperCase();
System.out.println("Limpio: '" + fullName + "'");
}
}

// Original: ' Ana María '
// Limpio: 'ANA MARÍA'

¿Qué es StringBuffer?

StringBuffer es una clase mutable y sincronizada, ideal para modificaciones frecuentes de texto, como concatenaciones en bucles. Cómo características principales podemos mencionar:

  • Mutable: Puedes cambiar su contenido sin crear nuevos objetos.
  • Thread-safe: Está sincronizado internamente: es seguro para múltiples hilos.
  • Más lento que StringBuilder: Por su sincronización interna.
  • Pertenece al paquete: java.lang.StringBuffer

¿Por qué no usar String para todo?

Recordemos que String es inmutable. Cada vez que haces una operación como:

String mensaje = "Hola";
mensaje += " mundo";

Internamente, Java crea un nuevo objeto con cada concatenación, lo cual consume más memoria y tiempo.

Con StringBuffer, puedes hacer esto de forma eficiente:

StringBuffer sb = new StringBuffer("Hola");
sb.append(" mundo"); // Se modifica el mismo objeto

String es como escribir en una hoja que luego tiras para escribir otra.

StringBuffer es un cuaderno donde puedes borrar, añadir o reescribir sin desechar la hoja.

Métodos más comunes de StringBuffer

MétodoEjemploResultado
append(String)sb.append(" Mundo")Añade al final
insert(int, String)sb.insert(5, "Java")Inserta en posición específica
replace(i, j, s)sb.replace(0, 4, "Hola")Reemplaza parte de la cadena
delete(i, j)sb.delete(0, 2)Elimina parte del texto
reverse()sb.reverse()Invierte el texto
toString()sb.toString()Devuelve el contenido como String

Ejemplo de uso de StringBuffer

En que proyectos usar StringBuffer

Caso de uso¿Por qué usar StringBuffer?
Editores de textoModificaciones dinámicas de cadenas
Generación de reportesConcatenación de grandes volúmenes de texto
Logs sincronizadosVarios hilos escribiendo en buffer compartido
Procesamiento de comandosConstrucción de mensajes complejos dinámicamente

¿Ques es StringBuilder?

StringBuilder es una clase de Java que permite crear y modificar cadenas de texto de forma eficiente y mutable. A diferencia de String (inmutable), StringBuilder permite modificar la misma instancia sin generar nuevos objetos cada vez que se cambia el contenido.

Fue introducida en Java 5 como una versión no sincronizada de StringBuffer, pensada para uso en un solo hilo (no thread-safe).

¿Por qué usar StringBuilder?

Situación¿Usar StringBuilder?
Concatenar texto dentro de bucles grandes
Generar contenido dinámico rápidamente
Operaciones de texto en interfaz gráfica
Aplicaciones multihiloNo. Mejor usar StringBuffer
Texto fijo o de solo lecturaNo. Mejor Usar String

Características clave de StringBuilder

CaracterísticaValor
MutableSi
SincronizadoNo, pero es más rápido que StringBuffer
VelocidadAlta
Pertenece ajava.lang
Hereda deAbstractStringBuilder
Compatible conCharSequence

Métodos más comunes

MétodoEjemploResultado
append(String)sb.append("Hola")Agrega texto al final
insert(int, String)sb.insert(5, "Mundo")Inserta texto en posición
replace(i, j, String)sb.replace(0, 4, "Hola")Reemplaza parte del texto
delete(i, j)sb.delete(0, 3)Elimina parte del contenido
reverse()sb.reverse()Invierte el texto
toString()sb.toString()Convierte a String
length()sb.length()Devuelve el número de caracteres
capacity()sb.capacity()Capacidad del buffer interno

Ejemplo de uso de StringBuilder

Comparativa

... de conceptos

ClaseInmutableHilo seguroRápida en 1 hiloRecomendado para…
StringNo aplicaTexto estático, solo lectura
StringBufferLentoConcatenación multihilo segura
StringBuilderRápidoConcatenaciones en apps locales

... de Rendimiento (String, StringBuffer, StringBuilder)

StringConcatBenchmark.java
public class StringConcatBenchmark {
public static void main(String[] args) {
final int ITERATIONS = 100_000;

// String (inmutable)
long start1 = System.nanoTime();
String text = "";
for (int i = 0; i < ITERATIONS; i++) {
text += "a";
}
long end1 = System.nanoTime();
System.out.println("String: " + ((end1 - start1) / 1_000_000) + " ms");

// StringBuffer (mutable + sincronizado)
long start2 = System.nanoTime();
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < ITERATIONS; i++) {
buffer.append("a");
}
long end2 = System.nanoTime();
System.out.println("StringBuffer: " + ((end2 - start2) / 1_000_000) + " ms");

// StringBuilder (mutable + no sincronizado)
long start3 = System.nanoTime();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < ITERATIONS; i++) {
builder.append("a");
}
long end3 = System.nanoTime();
System.out.println("StringBuilder: " + ((end3 - start3) / 1_000_000) + " ms");
}
}

Los resultados que podemos esperar son:

TipoTiempo esperado (100,000 repeticiones)
StringMuy lento (cientos de ms o más)
StringBufferMejor (30-100 ms)
StringBuilderMejor rendimiento (10-50 ms)

Mini-Proyecto: Gestor de Registro de Incidentes

Enunciado

Un sistema institucional necesita registrar, clasificar y mostrar incidentes reportados por los usuarios. Cada incidente debe tener:

  • Una descripción escrita (editable).
  • Un tipo definido (SOFTWARE, HARDWARE, NETWORK, USER).
  • Un estado (NEW, IN_PROGRESS, RESOLVED, CLOSED).
  • Una salida final formateada con StringBuffer.

La estructura básica e ideal del proyecto sería:

  • enum IncidentType
  • enum IncidentStatus
  • class Incident
  • class IncidentFormatter
  • class IncidentManager

Requisitos

  1. Crear los enums IncidentType y IncidentStatus con valores descriptivos.
  2. Crear clase Incident que contenga:
    • id (String)
    • description (StringBuffer)
    • type (IncidentType)
    • status (IncidentStatus)
  3. Implementar métodos para:
    • Modificar descripción con StringBuffer (append, replace, delete).
    • Cambiar el estado del incidente.
    • Mostrar un resumen formateado del incidente con toString() usando StringBuffer.
  4. Registrar al menos 5 incidentes simulados.
  5. Mostrar todos los incidentes ordenados por estado o tipo.

Ejemplo de salida esperada

[INC0003] NETWORK - NEW
Descripción: Usuario no puede conectarse a WiFi institucional.
---------------------------------------------------------------
[INC0004] HARDWARE - RESOLVED
Descripción: Cambio de teclado en Sala de Sistemas 5.
---------------------------------------------------------------

Pistas

Distribución de clases por paquetes

Relaciones entre clases

Reflexión final

Aplicación de principios SOLID:

  • S - Single Responsibility: Cada enum representa una sola responsabilidad clara. StringBuffer solo se encarga de manipular texto mutable.
  • O - Open/Close: Puedes agregar nuevos comportamientos sin alterar clases existentes. Puedes extender StringBuffer creando funciones auxiliares sin modificar si código.
  • L - Liskov Substitution:: Puedes usar cualquier valor del enum sin romper lógica existente. Métodos que esperan CharSequence pueden aceptar CharSequence pueden aceptar String, StringBuilder o StringBuffer.

Aplicaciones prácticas en proyectos reales

Caso de uso¿Por qué usar StringBuffer?
Editores de textoModificaciones dinámicas de cadenas
Generación de reportesConcatenación de grandes volúmenes de texto
Logs sincronizadosVarios hilos escribiendo en buffer compartido
Procesamiento de comandosConstrucción de mensajes complejos dinámicamente

Recursos y Biografía