Saltar a contenido

UD2 · Sección 3 — La clase String en profundidad

Dato Valor
Unidad Didáctica UD2 — Programación Orientada a Objetos con la API de Java
Resultado de Aprendizaje RA2 — Escribe y prueba programas sencillos, reconociendo y aplicando los fundamentos de la programación orientada a objetos.
Sección 3 de 10 — La clase String en profundidad
Evaluación 1.ª Evaluación
Duración estimada 3 horas lectivas
Criterios de evaluación cubiertos CE 2.2 (escribe programas simples), CE 2.3 (instancia objetos a partir de clases predefinidas), CE 2.4 (utiliza métodos y propiedades), CE 2.5 (llamadas a métodos estáticos), CE 2.6 (utiliza parámetros), CE 2.8 (utiliza constructores)
Prerrequisitos UD1 completa, UD2 Secciones 1 y 2
Paquete del código de ejemplo dam.programacion.ud2
Herramientas JDK 25, IntelliJ IDEA Community, Maven 3.9.x

1. Punto de partida

String es la clase que más vas a usar en toda tu carrera como programador Java. Literalmente: cada programa que escribas manipulará texto de alguna forma, y casi todo ese texto pasará por un String. Por eso esta sección es más larga y densa que las anteriores: merece la pena invertir tiempo en conocerla a fondo.

Hasta ahora has usado String como una caja negra: escribías literales entre comillas, los concatenabas con + y los mostrabas por consola. Ahora vamos a abrir la caja y ver qué hay dentro. Vas a descubrir dos cosas: una, que String tiene una particularidad muy importante (es inmutable) que condiciona todo su comportamiento. Dos, que tiene casi cincuenta métodos públicos que resuelven la mayoría de problemas de manipulación de texto sin que tengas que escribir lógica manual.

Al terminar esta sección serás capaz de buscar dentro de un texto, transformarlo, extraer partes, compararlo y formatearlo sin recurrir a bucles manuales. Es decir: dejarás de "pelear" con los strings y empezarás a "trabajar" con ellos.


2. Inmutabilidad y string interning

2.1. Inmutabilidad: qué significa

Un String es inmutable: una vez creado, su contenido no puede cambiar. Cualquier método que parezca modificar un String (toUpperCase(), replace(), trim()) en realidad devuelve un String nuevo y deja el original intacto.

1
2
3
4
String nombre = "Maria";
String mayus = nombre.toUpperCase();  // devuelve un NUEVO String "MARIA"
System.out.println(nombre);  // Maria  -> el original NO ha cambiado
System.out.println(mayus);   // MARIA

Analogía del libro de piedra. Imagina que cada String es un libro tallado en piedra. Si quieres "cambiarlo" a mayúsculas, no puedes modificar la piedra: necesitas tallar un libro nuevo con el texto en mayúsculas. El original sigue existiendo, intacto.

2.2. Por qué Java lo diseñó así

La inmutabilidad tiene tres ventajas clave:

  1. Seguridad: si un String se pasa como parámetro a un método, el método no puede modificarlo. Esto es crítico en contraseñas, URLs, nombres de fichero.
  2. Eficiencia en concurrencia: varios hilos pueden leer el mismo String sin bloqueos, porque nadie puede cambiarlo.
  3. Posibilidad de pooling: como los strings no cambian, Java puede reutilizarlos (lo veremos a continuación).

2.3. String interning: el string pool

Como ya vimos en la Sección 1, Java mantiene una zona especial del heap llamada string pool. Cuando escribes un literal como "Maria", Java lo añade al pool; si más adelante escribes otro "Maria", reutiliza el mismo objeto en vez de crear uno nuevo.

1
2
3
4
5
6
7
String a = "Maria";
String b = "Maria";
String c = new String("Maria");

System.out.println(a == b);        // true  (mismo objeto del pool)
System.out.println(a == c);        // false (new crea fuera del pool)
System.out.println(a.equals(c));   // true  (mismo contenido)

Trampa. Usar new String("Maria") es casi siempre un error: crea un objeto en el heap fuera del pool y desperdicia memoria. Usa siempre literales o métodos que devuelvan String.

2.4. Método intern()

Si por algún motivo tienes un String fuera del pool (por ejemplo, uno creado con new o uno leído de un fichero) y quieres meterlo en el pool, puedes llamar a intern(). Devuelve una referencia al objeto equivalente del pool (o lo añade si no existe). Es avanzado y rara vez se usa; lo mencionamos para que no te pille por sorpresa si lo ves en código ajeno.

Use mouse to pan and zoom
flowchart TB
    L["Literal 'Maria'"] --> P["String Pool"]
    P --> A["Variable a"]
    P --> B["Variable b"]
    N["new String('Maria')"] --> H["Heap (fuera del pool)"]
    H --> C["Variable c"]
    P -.intern().-> H

3. Métodos de búsqueda

Estos métodos no modifican el String original; solo devuelven información sobre él.

Método Qué hace Devuelve
int length() Longitud de la cadena int
boolean isEmpty() ¿Está vacía? (longitud 0) boolean
boolean isBlank() ¿Está en blanco? (longitud 0 o solo espacios) boolean
boolean contains(CharSequence) ¿Contiene la subcadena indicada? boolean
boolean startsWith(String) ¿Empieza por...? boolean
boolean endsWith(String) ¿Termina por...? boolean
int indexOf(String) Posición de la primera aparición int (-1 si no existe)
int lastIndexOf(String) Posición de la última aparición int (-1 si no existe)
char charAt(int) Carácter en la posición indicada char

Ejemplos:

String texto = "Hola, mundo";

System.out.println(texto.length());           // 11
System.out.println(texto.isEmpty());          // false
System.out.println(texto.isBlank());          // false

System.out.println(texto.contains("mundo"));  // true
System.out.println(texto.startsWith("Hola")); // true
System.out.println(texto.endsWith("mundo"));  // true

System.out.println(texto.indexOf("o"));       // 1 (primera 'o')
System.out.println(texto.lastIndexOf("o"));   // 10 (última 'o')
System.out.println(texto.indexOf("z"));       // -1 (no existe)

System.out.println(texto.charAt(0));          // 'H'
System.out.println(texto.charAt(7));          // 'm'

Trampa de isBlank() vs isEmpty():

1
2
3
4
5
6
String a = "";
String b = "   ";
System.out.println(a.isEmpty());   // true
System.out.println(a.isBlank());   // true
System.out.println(b.isEmpty());   // false (tiene 3 caracteres)
System.out.println(b.isBlank());   // true  (solo espacios)

isBlank() se añadió en Java 11. Para Java 25 está totalmente disponible.

Rangos de índices

Los índices en Java empiezan en 0. Para una cadena de longitud n, los índices válidos van de 0 a n-1. Pasar un índice fuera de rango a charAt lanza StringIndexOutOfBoundsException.

1
2
3
4
String s = "Java";   // indices 0..3
System.out.println(s.charAt(0));  // 'J'
System.out.println(s.charAt(3));  // 'a'
// System.out.println(s.charAt(4));  // StringIndexOutOfBoundsException

4. Métodos de transformación

Estos métodos devuelven un nuevo String; el original no cambia.

Método Qué hace
String toUpperCase() Convierte a mayúsculas
String toLowerCase() Convierte a minúsculas
String trim() Elimina espacios al inicio y al final (solo ASCII <= U+0020)
String strip() Como trim() pero Unicode completo (recomendado desde Java 11)
String stripLeading() Elimina espacios solo al inicio
String stripTrailing() Elimina espacios solo al final
String replace(char, char) Reemplaza todas las apariciones de un char por otro
String replace(CharSequence, CharSequence) Reemplaza subcadenas
String replaceAll(String regex, String repl) Reemplaza usando expresiones regulares
String replaceFirst(String regex, String repl) Reemplaza solo la primera aparición (regex)
String repeat(int) Repite la cadena n veces (Java 11+)

Ejemplos:

String s = "  Hola, Mundo  ";

System.out.println(s.toUpperCase());         // "  HOLA, MUNDO  "
System.out.println(s.toLowerCase());         // "  hola, mundo  "
System.out.println(s.trim());                // "Hola, Mundo"
System.out.println(s.strip());               // "Hola, Mundo" (preferido)
System.out.println(s.stripLeading());        // "Hola, Mundo  "
System.out.println(s.stripTrailing());       // "  Hola, Mundo"

System.out.println("Java".replace('a', 'o'));         // "Jovo"
System.out.println("Java".replace("a", "ee"));        // "Jeevee"
System.out.println("a1b2c3".replaceAll("[0-9]", "-"));   // "a-b-c-"
System.out.println("a1b2c3".replaceFirst("[0-9]", "-")); // "a-b2c3"

System.out.println("ab".repeat(3));          // "ababab"
System.out.println("-".repeat(20));          // "--------------------"

trim() vs strip()

trim() es histórico (existe desde Java 1.0) y solo elimina caracteres ASCII con código <= U+0020 (espacio, tab, salto de línea, retorno de carro). strip() se añadió en Java 11 y usa la definición Unicode de "espacio en blanco", que incluye caracteres como el espacio inseparable (\u00A0) o espacios de anchura completa de los idiomas asiáticos (\u3000). En código nuevo, usa siempre strip().


5. Extracción: substring, split y chars

5.1. substring

String substring(int beginIndex)
String substring(int beginIndex, int endIndex)

Devuelve una porción de la cadena original. beginIndex es inclusivo, endIndex es exclusivo (es decir, el carácter en endIndex no se incluye).

1
2
3
4
5
String s = "Hola, mundo";

System.out.println(s.substring(0, 4));   // "Hola"
System.out.println(s.substring(6));      // "mundo" (desde el indice 6 hasta el final)
System.out.println(s.substring(6, 8));   // "mu"

Analogía del pan. Imagina que el String es una barra de pan y substring es el cuchillo. substring(0, 4) corta desde el inicio hasta la cuarta marca (sin incluirla). La barra original sigue entera; el cuchillo solo te entrega una rebanada.

5.2. split

String[] split(String regex)
String[] split(String regex, int limit)

Divide la cadena en un array de subcadenas usando un separador (expresión regular). Devuelve un String[], que es un array de strings.

String csv = "Maria,Carlos,Ana,Luis";
String[] nombres = csv.split(",");

for (String nombre : nombres) {
    System.out.println(nombre);
}
// Maria
// Carlos
// Ana
// Luis

System.out.println(nombres.length);   // 4
System.out.println(nombres[0]);       // Maria
System.out.println(nombres[3]);       // Luis

Trampa: el separador es una regex. Si usas . como separador, no funciona como esperas:

1
2
3
String ip = "192.168.1.1";
String[] partes = ip.split(".");     // [] - el punto en regex significa "cualquier caracter"
String[] partesOk = ip.split("\\."); // ["192", "168", "1", "1"] - correcto

Por ahora basta con saber que si tu separador contiene caracteres especiales (. * + ? | ( ) [ { ^ $), debes escaparlos con \\. Las expresiones regulares en sí se verán más adelante en el módulo.

5.3. chars

IntStream chars()

Devuelve un IntStream con los códigos Unicode de cada carácter. Es un adelanto de la Streams API, que se verá a fondo en la UD6. Aquí lo mencionamos para que lo reconozcas si lo ves:

"Java".chars().forEach(c -> System.out.print((char) c + " "));
// J a v a

6. Construcción: String.join, .formatted, .repeat

Ya vimos repeat en la sección de transformación. Aquí veremos otras dos formas de construir strings nuevas a partir de piezas.

6.1. String.join (método estático)

String.join(CharSequence delimiter, CharSequence... elements)

Es la operación inversa de split: une varios strings con un separador. Es un método estático de la clase String.

1
2
3
4
5
String resultado = String.join(", ", "Maria", "Carlos", "Ana", "Luis");
System.out.println(resultado);   // "Maria, Carlos, Ana, Luis"

String ruta = String.join("/", "home", "usuario", "docs", "notas.txt");
System.out.println(ruta);   // "home/usuario/docs/notas.txt"

6.2. String.format y .formatted (métodos estático y de instancia)

Ya vistos en UD1, los recordamos aquí porque encajan temáticamente. Permiten construir un string a partir de una plantilla con marcadores.

1
2
3
4
5
6
// Metodo estatico
String s1 = String.format("Hola, %s. Tienes %d anos.", "Maria", 23);

// Metodo de instancia (Java 15+)
String s2 = "Hola, %s. Tienes %d anos.".formatted("Maria", 23);
// Ambos devuelven: "Hola, Maria. Tienes 23 anos."

Especificadores más usados:

Especificador Tipo Ejemplo
%s String (cualquier objeto con toString()) "Hola, %s".formatted("Maria")
%d Entero (int, long) "Edad: %d".formatted(23)
%f Decimal (float, double) "PI: %f".formatted(Math.PI)
%n Salto de línea independiente del SO "Linea 1%nLinea 2".formatted()
%.2f Decimal con 2 decimales "%.2f".formatted(3.14159) → "3.14"
%05d Entero con ceros a la izquierda (5 dígitos) "%05d".formatted(42) → "00042"

7. Comparación correcta: equals, equalsIgnoreCase, compareTo

7.1. equals y equalsIgnoreCase

boolean equals(Object)
boolean equalsIgnoreCase(String)

Comparan el contenido. equals distingue mayúsculas de minúsculas; equalsIgnoreCase no.

1
2
3
4
5
String a = "Maria";
String b = "maria";

System.out.println(a.equals(b));              // false
System.out.println(a.equalsIgnoreCase(b));    // true

Regla de oro: usa siempre .equals() para comparar strings por contenido. Nunca ==.

7.2. compareTo y compareToIgnoreCase

int compareTo(String otro)

Devuelve:

  • Un número negativo si este string va antes que otro (en orden lexicográfico).
  • 0 si son iguales.
  • Un número positivo si este string va después que otro.

Es el equivalente a los operadores <, ==, > pero para strings.

1
2
3
System.out.println("Ana".compareTo("Maria"));    // negativo (A < M)
System.out.println("Maria".compareTo("Maria"));  // 0
System.out.println("Maria".compareTo("Ana"));    // positivo (M > A)

Casos típicos: ordenar alfabéticamente una lista de nombres (se verá en UD6 con List.sort), verificar si una contraseña está dentro de un rango de seguridad.

1
2
3
4
5
6
7
8
9
String clave = "avocado";
if (clave.compareTo("azul") < 0) {
    System.out.println("Va antes que 'azul'");
} else if (clave.compareTo("azul") == 0) {
    System.out.println("Es 'azul'");
} else {
    System.out.println("Va despues de 'azul'");
}
// Imprime: Va despues de 'azul'

7.3. Tabla resumen de comparación

Método Qué compara Devuelve ¿Sensible a mayúsculas?
== Referencias (dirección de memoria) boolean —
.equals(String) Contenido boolean Sí
.equalsIgnoreCase(String) Contenido boolean No
.compareTo(String) Orden lexicográfico int (neg/0/pos) Sí
.compareToIgnoreCase(String) Orden lexicográfico int (neg/0/pos) No

8. Comprobación: isEmpty, isBlank

Ya los mencionamos en la sección de búsqueda, pero conviene recordarlos como categoría aparte porque se usan muchísimo en validaciones:

String input = "";

if (input.isEmpty()) {
    System.out.println("El usuario no ha escrito nada");
}

String input2 = "   ";
if (input2.isBlank()) {
    System.out.println("Solo ha escrito espacios");
}

En validación de formularios (que verás más adelante en el curso), isBlank() suele ser la opción correcta: "no me valen ni la cadena vacía ni la cadena solo con espacios".


9. Text blocks: literales multilínea (Java 15+)

Ya introducidos en UD1, los recordamos porque encajan en el temario de String. Permiten escribir strings de varias líneas sin escapar comillas ni saltos de línea.

1
2
3
4
5
6
7
8
String json = """
        {
          "nombre": "Maria",
          "edad": 23,
          "ciudad": "Alicante"
        }
        """;
System.out.println(json);

Reglas básicas:

  • Empiezan con """ seguido de un salto de línea.
  • Terminan con """ en su propia línea.
  • La indentación se ajusta automáticamente a la del cierre """.

Son ideales para HTML, JSON, SQL, mensajes largos.


10. Ejemplo integrador

Programa que combina los conceptos de la sección. Imagina que estás construyendo un sistema que valida y normaliza correos electrónicos.

package dam.programacion.ud2;

/**
 * Ejemplo integrador de la Seccion 3 de UD2.
 * Demuestra:
 * - Inmutabilidad de String (los metodos devuelven nuevos String)
 * - Metodos de busqueda: contains, startsWith, endsWith, indexOf, charAt
 * - Metodos de transformacion: toLowerCase, strip, replace
 * - Extraccion: substring, split
 * - Comparacion: equals, equalsIgnoreCase, compareTo
 * - Formateo: formatted
 */
public class ManipulandoStrings {

    public static void main(String[] args) {

        String email = "  Maria.Garcia@Example.COM  ";

        // 1. Normalizacion: eliminar espacios y pasar a minusculas
        String normalizado = email.strip().toLowerCase();
        System.out.println("Normalizado: " + normalizado);   // maria.garcia@example.com

        // 2. Validacion simple (sin regex, solo para demostrar metodos)
        if (normalizado.isBlank()) {
            System.out.println("Email vacio");
        } else if (!normalizado.contains("@")) {
            System.out.println("Falta el @");
        } else if (!normalizado.endsWith(".com") && !normalizado.endsWith(".es")) {
            System.out.println("Dominio no soportado");
        } else {
            System.out.println("Email valido");
        }

        // 3. Extraccion del usuario y dominio
        int arroba = normalizado.indexOf("@");
        String usuario = normalizado.substring(0, arroba);
        String dominio = normalizado.substring(arroba + 1);
        System.out.println("Usuario: " + usuario);    // maria.garcia
        System.out.println("Dominio: " + dominio);    // example.com

        // 4. Transformacion del usuario: reemplazar el punto
        String usuarioSinPuntos = usuario.replace(".", "_");
        System.out.println("Usuario sin puntos: " + usuarioSinPuntos);   // maria_garcia

        // 5. Comparacion con otro email
        String otroEmail = "MARIA.GARCIA@example.com";
        System.out.println("Iguales con equals: " + normalizado.equals(otroEmail));             // false
        System.out.println("Iguales con equalsIgnoreCase: " + normalizado.equalsIgnoreCase(otroEmail));  // true

        // 6. Orden lexicografico
        System.out.println("compareTo Ana: " + usuario.compareTo("Ana"));   // positivo
        System.out.println("compareTo Zara: " + usuario.compareTo("Zara")); // negativo

        // 7. Formateo final
        String resumen = "Usuario %s con dominio %s (longitud total %d)".formatted(
                usuarioSinPuntos, dominio, normalizado.length());
        System.out.println(resumen);

        // 8. Repeticion para separadores
        System.out.println("-".repeat(40));

        // 9. Split de dominio por el punto
        String[] partesDominio = dominio.split("\\.");
        System.out.println("Partes del dominio: " + partesDominio.length);   // 2
        for (String parte : partesDominio) {
            System.out.println(" - " + parte);
        }
        //  - example
        //  - com
    }
}

Salida esperada:

Normalizado: maria.garcia@example.com
Email valido
Usuario: maria.garcia
Dominio: example.com
Usuario sin puntos: maria_garcia
Iguales con equals: false
Iguales con equalsIgnoreCase: true
compareTo Ana: 12
compareTo Zara: -13
Usuario maria_garcia con dominio example.com (longitud total 22)
----------------------------------------
Partes del dominio: 2
 - example
 - com

Antes de ejecutarlo, intenta predecir la salida. Si aciertas, has entendido la sección.


11. Errores comunes

Error Qué pasa Cómo evitarlo
Usar == para comparar strings Compara referencias, no contenido Usa siempre .equals() o .equalsIgnoreCase()
Olvidar que String es inmutable Llamar a s.toUpperCase(); y esperar que s cambie Asigna el resultado: s = s.toUpperCase();
Confundir substring inclusivo/exclusivo substring(0, 4) devuelve 4 caracteres, no 5 Recuerda: endIndex es exclusivo
Usar split(".") directamente Devuelve array vacío (el punto es regex) Escapa: split("\\.")
Confundir trim() con strip() trim no elimina espacios Unicode raros Usa strip() en código nuevo
Pasar índices fuera de rango a charAt StringIndexOutOfBoundsException Comprueba length() antes
Usar new String("...") Desperdicia memoria (crea fuera del pool) Usa literales directamente

12. Resumen

Categoría Métodos clave
Búsqueda length, isEmpty, isBlank, contains, startsWith, endsWith, indexOf, lastIndexOf, charAt
Transformación toUpperCase, toLowerCase, trim, strip, stripLeading, stripTrailing, replace, replaceAll, replaceFirst, repeat
Extracción substring, split, chars
Construcción String.join, String.format, .formatted, +, repeat
Comparación equals, equalsIgnoreCase, compareTo, compareToIgnoreCase
Inmutabilidad Ningún método modifica el original; todos devuelven nuevos String
Multilínea Text blocks """...""" (Java 15+)

13. Cuestionario de autoevaluación

Preguntas

  1. ¿Qué significa que String sea inmutable? Pon un ejemplo de código que lo demuestre.

  2. ¿Cuál es la diferencia entre == y .equals() al comparar dos strings?

  3. ¿Qué es el string pool y por qué new String("Maria") suele ser una mala idea?

  4. ¿Cuál es la diferencia entre trim() y strip()? ¿Cuál deberías usar en código nuevo?

  5. ¿Qué devuelve "Hola, mundo".substring(6)? ¿Y "Hola, mundo".substring(0, 4)?

  6. ¿Por qué "192.168.1.1".split(".") no devuelve ["192", "168", "1", "1"]? ¿Cómo se soluciona?

  7. ¿Qué devuelve "Maria".compareTo("Ana")? ¿Y "Ana".compareTo("Maria")? ¿Y "Maria".compareTo("Maria")?

  8. ¿Qué método usarías para comprobar si un string está compuesto solo por espacios? ¿Por qué isEmpty() no sería suficiente?

  9. Escribe una línea que devuelva "Hola Maria" a partir de " hola maria " (sin espacios, con la H y la M en mayúsculas).

  10. ¿Cuál es la diferencia entre isEmpty() e isBlank()? Pon un ejemplo con la cadena " ".

  11. ¿Qué imprime el siguiente código?

    1
    2
    3
    String s = "Java";
    s.toUpperCase();
    System.out.println(s);
    
  12. ¿Cómo se escriben los especificadores de formato para: (a) un string, (b) un entero, (c) un decimal con 2 decimales, (d) un salto de línea portable?

  13. ¿Qué método permite repetir un string N veces? ¿Desde qué versión de Java está disponible?

  14. ¿Qué diferencia hay entre replace(char, char) y replaceAll(String, String)?

  15. Escribe una sola línea de código que una los strings "Maria", "Carlos" y "Ana" con el separador ", " usando un método estático de String.

Soluciones

  1. Significa que, una vez creado, el contenido de un String no puede cambiar. Cualquier método que parezca modificarlo devuelve un String nuevo. Ejemplo:

    1
    2
    3
    String s = "Maria";
    s.toUpperCase();                 // el resultado se descarta
    System.out.println(s);           // sigue imprimiendo "Maria"
    
    Para que surta efecto hay que asignar: s = s.toUpperCase();.

  2. == compara referencias (direcciones de memoria); .equals() compara contenidos. == puede dar true accidentalmente con literales del pool, pero falla con strings creados con new o leídos de fichero.

  3. El string pool es una zona del heap donde Java guarda los literales de string y los reutiliza. new String("Maria") crea un objeto nuevo fuera del pool, desperdiciando memoria, porque ya existe "Maria" en el pool. Basta con usar el literal "Maria".

  4. trim() elimina solo espacios ASCII con código <= U+0020; strip() (Java 11+) usa la definición Unicode completa. En código nuevo, usa siempre strip().

  5. "Hola, mundo".substring(6) devuelve "mundo" (desde el índice 6 hasta el final). "Hola, mundo".substring(0, 4) devuelve "Hola" (índice 0 incluido, índice 4 excluido: 4 caracteres).

  6. Porque el separador que recibe split es una expresión regular, y en regex el punto . significa "cualquier carácter". Solución: escapar con split("\\.").

  7. "Maria".compareTo("Ana") devuelve un número positivo (porque "Maria" va después de "Ana"). "Ana".compareTo("Maria") devuelve un número negativo. "Maria".compareTo("Maria") devuelve 0.

  8. isBlank(). isEmpty() devuelve false para " " porque tiene 3 caracteres, pero para nosotros suele ser un valor "vacío" en términos de validación.

  9. " hola maria ".strip().replace("hola", "Hola").replace("maria", "Maria") o, más conciso, " hola maria ".strip() seguido de operaciones de capitalización (la capitalización correcta de la primera letra de cada palabra requiere lógica que verás en unidades avanzadas; para esta pregunta basta con replace).

  10. isEmpty() devuelve false para " " (tiene 3 caracteres). isBlank() devuelve true (solo contiene espacios).

  11. Imprime Java. La llamada a toUpperCase() devuelve un nuevo String que se descarta porque no se asigna a ninguna variable.

  12. (a) %s, (b) %d, (c) %.2f, (d) %n.

  13. repeat(int), disponible desde Java 11.

  14. replace(char, char) y replace(CharSequence, CharSequence) reemplazan literalmente (sin interpretar regex). replaceAll(String, String) interpreta el primer argumento como una expresión regular. Para reemplazos literales usa replace; para patrones usa replaceAll.

  15. String.join(", ", "Maria", "Carlos", "Ana").

Evaluación del cuestionario

Aciertos Nivel
14-15 Dominas la sección. Adelante con la siguiente.
10-13 Bien, repasa los puntos fallados.
6-9 Repasa la sección, especialmente inmutabilidad e índices.
Menos de 6 Vuelve a leer con calma y ejecuta el ejemplo integrador línea por línea en IntelliJ.

14. Información ampliada y próximos pasos

Próximos pasos:

  1. Practica en IntelliJ. Copia el ejemplo integrador, ejecútalo, modifícalo: prueba a cambiar el email por uno sin arroba, por uno solo con espacios, por uno con mayúsculas y minúsculas mezcladas. Observa el comportamiento.
  2. Lee el Javadoc de String. Recorre la lista de métodos públicos y prueba los que no hayamos visto en clase (por ejemplo, indent, transform, chars). Es un ejercicio excelente de exploración del API.
  3. Avanza a la Sección 4 de UD2. La clase Math: constantes, funciones matemáticas, Math.clamp (Java 21+) y la introducción a la generación de aleatorios con Math.random(). Es una sección más corta y ligera, ideal para asentar lo aprendido aquí antes de entrar en Random y java.time en las secciones 5 y 6.