Las clases de utilidad de Java son herramientas predefinidas que todo programador utiliza constantemente. Proporcionan métodos estáticos para realizar operaciones comunes — desde ordenar arrays y manipular cadenas de texto hasta cálculos matemáticos y conversión de tipos — sin necesidad de implementarlas desde cero.
En este artículo estudiaremos las clases de utilidad más importantes del JDK: comenzando por los arrays (la estructura de datos más básica), la clase Arrays con sus métodos de manipulación, String y StringBuilder para cadenas, Math para cálculos, las clases wrapper para envolver primitivos, y Collections para listas y mapas. Cada sección incluye código ejecutable y ejemplos prácticos.
📖 ¿Qué son las clases de utilidad?
Una clase de utilidad (también llamada helper class) es una clase que contiene solo métodos static y, por convención, un constructor privado para impedir su instanciación. No representan un «objeto» del mundo real, sino que agrupan funcionalidades relacionadas.
| Clase | Paquete | Función principal |
|---|---|---|
Arrays | java.util | Ordenar, buscar, copiar y comparar arrays |
String | java.lang | Representar y manipular cadenas de texto inmutables |
StringBuilder | java.lang | Construir cadenas de forma eficiente (mutable) |
Math | java.lang | Funciones matemáticas (raíz, potencia, trigonometría...) |
Integer, Double... | java.lang | Envolver primitivos como objetos (wrappers) |
Collections | java.util | Ordenar, buscar y transformar colecciones |
🗃️ Arrays (vectores)
Un array (vector) es una estructura que agrupa un conjunto de valores del mismo tipo bajo un mismo nombre. Se accede a cada elemento mediante un índice numérico que comienza en 0. Los arrays en Java son objetos con tamaño fijo, definido al crearlos.
📋 Declaración y creación
// Dos formas de declarar (la segunda es preferida)
int vector1[]; // estilo C
int[] vector2; // estilo Java (recomendado)
// Crear con tamaño fijo (30 elementos, inicializados a 0)
int[] numeros = new int[30];
// Crear e inicializar con valores entre llaves
int[] notas = {8, 9, 7, 10, 6, 8};
// Es equivalente a:
int[] notas2 = new int[6];
notas2[0] = 8;
notas2[1] = 9;
notas2[2] = 7;
notas2[3] = 10;
notas2[4] = 6;
notas2[5] = 8;
🔍 Acceso y recorrido
int[] notas = {8, 9, 7, 10, 6, 8};
// Acceder por índice (0 a length-1)
System.out.println("Primera nota: " + notas[0]); // 8
System.out.println("Última nota: " + notas[notas.length - 1]); // 8
// Recorrido con for clásico
System.out.println("Notas con for:");
for (int i = 0; i < notas.length; i++) {
System.out.println(" Nota " + i + ": " + notas[i]);
}
// Recorrido con for-each (más limpio)
System.out.println("Notas con for-each:");
for (int nota : notas) {
System.out.println(" → " + nota);
}
📊 Valores por defecto
Al crear un array con new, cada posición se inicializa automáticamente según el tipo:
| Tipo | Valor por defecto | Ejemplo |
|---|---|---|
int, long, short, byte | 0 | new int[5] → {0, 0, 0, 0, 0} |
float, double | 0.0 | new double[3] → {0.0, 0.0, 0.0} |
char | '\u0000' (nulo) | Carácter nulo |
boolean | false | new boolean[2] → {false, false} |
String y objetos | null | new String[3] → {null, null, null} |
🔹 Argumentos de la línea de comandos
El parámetro String[] args del método main es un array que recibe los argumentos de la línea de comandos:
public class Imprime {
public static void main(String[] args) {
for (String arg : args) {
System.out.print(arg + " ");
}
}
}
// Ejecución: java Imprime hola que tal estas
// Salida: hola que tal estas
🛠️ La clase java.util.Arrays
La clase Arrays proporciona métodos estáticos para las operaciones más habituales con arrays: ordenar, buscar, copiar, comparar y representar como cadena.
| Método | Descripción | Complejidad |
|---|---|---|
sort(a) | Ordena el array en orden ascendente | O(n log n) |
binarySearch(a, key) | Busca key en un array ya ordenado | O(log n) |
copyOf(a, len) | Copia los primeros len elementos | O(n) |
copyOfRange(a, from, to) | Copia un rango del array | O(n) |
fill(a, val) | Rellena todas las posiciones con val | O(n) |
equals(a, b) | Compara si dos arrays tienen el mismo contenido | O(n) |
toString(a) | Devuelve una representación legible | O(n) |
stream(a) | Convierte el array en un Stream | O(1) |
import java.util.Arrays;
public class DemoArrays {
public static void main(String[] args) {
int[] numeros = {42, 15, 8, 99, 23, 67, 4};
// toString: representación legible
System.out.println("Original: " + Arrays.toString(numeros));
// [42, 15, 8, 99, 23, 67, 4]
// sort: ordenar
Arrays.sort(numeros);
System.out.println("Ordenado: " + Arrays.toString(numeros));
// [4, 8, 15, 23, 42, 67, 99]
// binarySearch: buscar (requiere array ordenado)
int pos = Arrays.binarySearch(numeros, 23);
System.out.println("23 está en posición: " + pos); // 3
// copyOf: copiar
int[] copia = Arrays.copyOf(numeros, 4);
System.out.println("Copia: " + Arrays.toString(copia));
// [4, 8, 15, 23]
// fill: rellenar
int[] relleno = new int[5];
Arrays.fill(relleno, -1);
System.out.println("Relleno: " + Arrays.toString(relleno));
// [-1, -1, -1, -1, -1]
// equals: comparar contenido
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println("¿Iguales? " + Arrays.equals(a, b)); // true
System.out.println("¿Mismo objeto? " + (a == b)); // false
// stream: programación funcional
double media = Arrays.stream(numeros).average().orElse(0);
System.out.printf("Media: %.1f%n", media); // 36.9
}
}
📝 La clase String
String es probablemente la clase más utilizada en Java. Representa una cadena de caracteres inmutable: una vez creada, su contenido no puede modificarse. Cada operación que aparentemente modifica un String en realidad crea un nuevo objeto.
🔑 Métodos esenciales
| Método | Descripción | Ejemplo |
|---|---|---|
length() | Longitud de la cadena | "Java".length() → 4 |
charAt(i) | Carácter en la posición i | "Java".charAt(0) → 'J' |
substring(i, j) | Subcadena desde i hasta j-1 | "Hola Mundo".substring(5, 10) → "Mundo" |
indexOf(s) | Posición de la primera ocurrencia | "Java es genial".indexOf("es") → 5 |
contains(s) | ¿Contiene la subcadena? | "Java 21".contains("21") → true |
toUpperCase() | Convierte a mayúsculas | "java".toUpperCase() → "JAVA" |
toLowerCase() | Convierte a minúsculas | "JAVA".toLowerCase() → "java" |
trim() | Elimina espacios al inicio y final | " hola ".trim() → "hola" |
replace(a, b) | Reemplaza todas las ocurrencias | "aaa".replace("a","b") → "bbb" |
split(regex) | Divide en un array por el separador | "a,b,c".split(",") → ["a","b","c"] |
equals(s) | Compara contenido (NO usar ==) | "Java".equals("Java") → true |
String texto = " Programación en Java ";
String limpio = texto.trim(); // "Programación en Java"
String mayus = limpio.toUpperCase(); // "PROGRAMACIÓN EN JAVA"
String[] palabras = limpio.split(" "); // ["Programación", "en", "Java"]
boolean contiene = limpio.contains("Java"); // true
String reemplazo = limpio.replace("Java", "Python"); // "Programación en Python"
System.out.println("Palabras: " + palabras.length); // 3
System.out.println("Contiene Java: " + contiene); // true
System.out.println("Reemplazo: " + reemplazo);
⚡ StringBuilder y StringBuffer
Dado que String es inmutable, la concatenación repetida con + dentro de un bucle crea múltiples objetos temporales, lo que degrada el rendimiento. StringBuilder resuelve este problema: es una secuencia de caracteres mutable que permite añadir, insertar y modificar contenido sin crear objetos nuevos.
| Característica | String | StringBuilder | StringBuffer |
|---|---|---|---|
| Mutabilidad | Inmutable | Mutable | Mutable |
| Sincronizada | — | No (más rápida) | Sí (thread-safe) |
| Uso recomendado | Textos que no cambian | Construcción iterativa | Entornos multihilo |
// ❌ Ineficiente: crea un nuevo String en cada iteración
String resultado = "";
for (int i = 1; i <= 1000; i++) {
resultado += i + ", "; // 1000 objetos String temporales
}
// ✅ Eficiente: un solo objeto StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 1000; i++) {
sb.append(i);
if (i < 1000) sb.append(", ");
}
String resultado2 = sb.toString();
// Otros métodos útiles
StringBuilder sb2 = new StringBuilder("Hola");
sb2.append(" Mundo"); // "Hola Mundo"
sb2.insert(5, " Buen"); // "Hola Buen Mundo"
sb2.replace(0, 4, "¡Hola"); // "¡Hola Buen Mundo"
sb2.reverse(); // "odnuM neuB aloH¡"
System.out.println(sb2.length()); // 17
String para textos que no cambian, StringBuilder cuando construyas cadenas en bucles o condiciones, y StringBuffer solo si necesitas acceso concurrente desde múltiples hilos.🔢 La clase Math
La clase java.lang.Math contiene métodos estáticos para operaciones matemáticas comunes. Es final (no puede heredarse) y tiene un constructor privado (no puede instanciarse).
| Método | Descripción | Ejemplo |
|---|---|---|
abs(x) | Valor absoluto | Math.abs(-7) → 7 |
max(a, b) | Mayor de dos valores | Math.max(3, 9) → 9 |
min(a, b) | Menor de dos valores | Math.min(3, 9) → 3 |
pow(base, exp) | Potencia | Math.pow(2, 10) → 1024.0 |
sqrt(x) | Raíz cuadrada | Math.sqrt(144) → 12.0 |
round(x) | Redondeo al entero más próximo | Math.round(3.7) → 4 |
floor(x) | Redondeo hacia abajo | Math.floor(3.9) → 3.0 |
ceil(x) | Redondeo hacia arriba | Math.ceil(3.1) → 4.0 |
random() | Aleatorio entre 0.0 y 1.0 | Math.random() → 0.73... |
PI | Constante π | Math.PI → 3.14159... |
E | Constante e | Math.E → 2.71828... |
// Área de un círculo
double radio = 5.0;
double area = Math.PI * Math.pow(radio, 2);
System.out.printf("Área: %.2f%n", area); // 78.54
// Distancia entre dos puntos (teorema de Pitágoras)
double x1 = 3, y1 = 4, x2 = 7, y2 = 1;
double distancia = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
System.out.printf("Distancia: %.2f%n", distancia); // 5.00
// Número aleatorio entre 1 y 100
int aleatorio = (int) (Math.random() * 100) + 1;
System.out.println("Aleatorio: " + aleatorio);
📦 Clases wrapper (envoltorio)
Las colecciones genéricas de Java (ArrayList, HashMap) solo aceptan objetos, no tipos primitivos. Las clases wrapper envuelven cada primitivo en un objeto, y Java realiza la conversión automáticamente mediante autoboxing y unboxing.
| Primitivo | Wrapper | Método de conversión | Constantes útiles |
|---|---|---|---|
byte | Byte | Byte.parseByte("42") | MIN_VALUE, MAX_VALUE |
short | Short | Short.parseShort("42") | MIN_VALUE, MAX_VALUE |
int | Integer | Integer.parseInt("42") | MIN_VALUE, MAX_VALUE |
long | Long | Long.parseLong("42") | MIN_VALUE, MAX_VALUE |
float | Float | Float.parseFloat("3.14") | NaN, POSITIVE_INFINITY |
double | Double | Double.parseDouble("3.14") | NaN, POSITIVE_INFINITY |
char | Character | Character.isDigit('5') | isLetter(), isUpperCase() |
boolean | Boolean | Boolean.parseBoolean("true") | TRUE, FALSE |
// Autoboxing: primitivo → objeto (automático)
Integer numObj = 42; // equivale a Integer.valueOf(42)
Double piObj = 3.14; // equivale a Double.valueOf(3.14)
// Unboxing: objeto → primitivo (automático)
int num = numObj; // equivale a numObj.intValue()
double pi = piObj;
// Conversión String → primitivo
int edad = Integer.parseInt("25");
double precio = Double.parseDouble("19.99");
// Conversión primitivo → String
String edadStr = Integer.toString(25); // "25"
String precioStr = String.valueOf(19.99); // "19.99"
// Constantes útiles
System.out.println("int máximo: " + Integer.MAX_VALUE); // 2147483647
System.out.println("int mínimo: " + Integer.MIN_VALUE); // -2147483648
// Métodos de Character
System.out.println(Character.isDigit('5')); // true
System.out.println(Character.isLetter('A')); // true
System.out.println(Character.toUpperCase('a')); // 'A'
null: Los wrappers pueden ser null, a diferencia de los primitivos. Si haces unboxing de un wrapper null, se lanza NullPointerException: Integer x = null; int y = x; → ¡Error!🗂️ La clase Collections
La clase java.util.Collections (con «s» final, no confundir con la interfaz Collection) proporciona métodos estáticos para manipular colecciones como List, Set y Map. Es el equivalente de la clase Arrays pero orientado al framework de colecciones, y resulta imprescindible en cualquier proyecto Java de tamaño medio o grande.
| Método | Descripción | Ejemplo de uso |
|---|---|---|
sort(list) | Ordena la lista en orden natural | Ordenar nombres alfabéticamente |
reverse(list) | Invierte el orden de los elementos | Mostrar ranking de mayor a menor |
shuffle(list) | Mezcla aleatoriamente | Barajar cartas, preguntas de examen |
min(col) / max(col) | Devuelve el menor / mayor elemento | Encontrar el precio más bajo |
frequency(col, obj) | Cuenta cuántas veces aparece un elemento | Contar votos de un candidato |
unmodifiableList(list) | Devuelve una vista de solo lectura | Proteger datos de configuración |
import java.util.*;
public class DemoCollections {
public static void main(String[] args) {
List<String> ciudades = new ArrayList<>(
Arrays.asList("Madrid", "Barcelona", "Sevilla", "Valencia", "Bilbao")
);
// sort: ordenar alfabéticamente
Collections.sort(ciudades);
System.out.println("Ordenadas: " + ciudades);
// [Barcelona, Bilbao, Madrid, Sevilla, Valencia]
// reverse: invertir el orden
Collections.reverse(ciudades);
System.out.println("Invertidas: " + ciudades);
// [Valencia, Sevilla, Madrid, Bilbao, Barcelona]
// shuffle: mezclar aleatoriamente
Collections.shuffle(ciudades);
System.out.println("Mezcladas: " + ciudades);
// min y max
System.out.println("Mín: " + Collections.min(ciudades));
System.out.println("Máx: " + Collections.max(ciudades));
// frequency: contar ocurrencias
List<Integer> nums = Arrays.asList(1, 3, 5, 3, 7, 3, 9);
System.out.println("Veces que aparece 3: " + Collections.frequency(nums, 3)); // 3
// unmodifiableList: lista de solo lectura
List<String> soloLectura = Collections.unmodifiableList(ciudades);
// soloLectura.add("Málaga"); // ¡UnsupportedOperationException!
}
}
🏗️ Ejemplo integrador
El siguiente programa combina todas las clases de utilidad estudiadas para procesar un registro de calificaciones de estudiantes: usa arrays, Arrays, String, StringBuilder, Math e Integer en un único flujo coherente.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class GestorCalificaciones {
public static void main(String[] args) {
// Datos de entrada como cadenas (simula lectura de archivo)
String datos = "Ana:8,9,7;Luis:6,5,8;María:10,9,10;Pedro:4,6,3";
// Procesar cada estudiante
String[] estudiantes = datos.split(";");
List<String> resultados = new ArrayList<>();
StringBuilder informe = new StringBuilder();
informe.append("╔══════════════════════════════════════════╗\n");
informe.append("║ INFORME DE CALIFICACIONES ║\n");
informe.append("╠══════════════════════════════════════════╣\n");
double mediaGlobal = 0;
int totalEstudiantes = estudiantes.length;
for (String est : estudiantes) {
// Separar nombre y notas
String nombre = est.split(":")[0].trim();
String[] notasStr = est.split(":")[1].split(",");
// Convertir String[] a int[] usando wrapper Integer
int[] notas = new int[notasStr.length];
for (int i = 0; i < notasStr.length; i++) {
notas[i] = Integer.parseInt(notasStr[i].trim());
}
// Cálculos con Arrays y Math
double media = Arrays.stream(notas).average().orElse(0);
int maxNota = Arrays.stream(notas).max().orElse(0);
int minNota = Arrays.stream(notas).min().orElse(0);
String estado = media >= 5 ? "APROBADO ✅" : "SUSPENDIDO ❌";
// Construir línea del informe con StringBuilder
informe.append(String.format("║ %-8s | Notas: %-10s | Media: %.1f %s%n",
nombre, Arrays.toString(notas), media, estado));
resultados.add(nombre + ": " + String.format("%.1f", media));
mediaGlobal += media;
}
informe.append("╠══════════════════════════════════════════╣\n");
informe.append(String.format("║ Media global: %.2f%n", mediaGlobal / totalEstudiantes));
informe.append("╚══════════════════════════════════════════╝");
System.out.println(informe);
// Ordenar resultados con Collections
Collections.sort(resultados);
System.out.println("\nRanking alfabético: " + resultados);
}
}
❌ Errores frecuentes
🔹 Error 1: comparar Strings con ==
String a = new String("Java");
String b = new String("Java");
// ❌ Compara referencias (direcciones de memoria), NO contenido
System.out.println(a == b); // false
// ✅ Compara contenido
System.out.println(a.equals(b)); // true
🔹 Error 2: ArrayIndexOutOfBoundsException
int[] nums = {10, 20, 30};
// ❌ Índice 3 no existe (válidos: 0, 1, 2)
System.out.println(nums[3]); // 💥 ArrayIndexOutOfBoundsException
// ✅ Usar length para evitarlo
for (int i = 0; i < nums.length; i++) { // length = 3, itera 0, 1, 2
System.out.println(nums[i]);
}
🔹 Error 3: binarySearch en array no ordenado
int[] datos = {42, 15, 8, 99};
// ❌ binarySearch requiere array ORDENADO
int pos = Arrays.binarySearch(datos, 15); // Resultado impredecible
// ✅ Ordenar primero
Arrays.sort(datos); // [8, 15, 42, 99]
int pos2 = Arrays.binarySearch(datos, 15); // 1 (correcto)
📝 Ejercicios prácticos
Ejercicio 1: Estadísticas de un array
Dado el array {45, 78, 12, 95, 33, 67, 88, 21}, escribe un programa que calcule: la suma, la media, el máximo, el mínimo y cuántos elementos superan la media. Usa Arrays y Math.
Ejercicio 2: Analizador de texto
Escribe un programa que reciba una frase y muestre: número de caracteres, número de palabras, número de vocales, la frase invertida y la frase con cada palabra capitalizada.
Ejercicio 3: Conversor de temperaturas
Usando Math y String.format, escribe un programa que genere una tabla de conversión de Celsius a Fahrenheit y Kelvin para las temperaturas de 0 a 100 de 10 en 10. Fórmulas: F = C × 9/5 + 32 y K = C + 273.15.
❓ Preguntas frecuentes sobre Clases en Java de utilidad
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Clases en Java de utilidad? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!