Ir al contenido

UD02 · Ejercicios

Seis bloques, de menos a más. Haz cada bloque cuando hayas leído su apartado de la teoría, sin esperar a tenerla entera.

Todas las soluciones están plegadas y escritas con la sintaxis de Java 25. Si la tuya es distinta pero funciona y se entiende, es igual de válida: en programación casi nunca hay una única respuesta correcta.

Muestra por pantalla tu nombre, tu dirección y tu teléfono, cada uno en una línea.

Ver solución
Ficha.java
void main() {
IO.println("Lucía Martín Ruiz");
IO.println("Calle Real, 14 - Martos");
IO.println("600 123 456");
}

También vale con un bloque de texto, que para varias líneas seguidas queda más limpio:

void main() {
IO.println("""
Lucía Martín Ruiz
Calle Real, 14 - Martos
600 123 456
""");
}

Muestra diez palabras en inglés con su traducción, en dos columnas alineadas a la izquierda.

Ver solución
Diccionario.java
void main() {
IO.println("%-12s%s".formatted("INGLÉS", "CASTELLANO"));
IO.println("%-12s%s".formatted("house", "casa"));
IO.println("%-12s%s".formatted("computer", "ordenador"));
IO.println("%-12s%s".formatted("keyboard", "teclado"));
IO.println("%-12s%s".formatted("screen", "pantalla"));
IO.println("%-12s%s".formatted("file", "fichero"));
}

El \t de la pista funciona, pero descuadra en cuanto una palabra es más larga que el tabulador. %-12s reserva siempre 12 huecos y por eso las columnas quedan rectas.

Muestra tu horario de clase de la semana en forma de tabla, con los días como columnas.

Ver solución
Horario.java
void main() {
IO.println("%-10s%-14s%-14s%-14s".formatted("HORA", "LUNES", "MARTES", "MIÉRCOLES"));
IO.println("%-10s%-14s%-14s%-14s".formatted("08:15", "Programación", "Bases Datos", "Programación"));
IO.println("%-10s%-14s%-14s%-14s".formatted("09:15", "Sistemas", "Programación", "Entornos"));
IO.println("%-10s%-14s%-14s%-14s".formatted("10:15", "Markup", "Sistemas", "Bases Datos"));
}

Repetir la misma cadena de formato cuatro veces canta un poco. Cuando lleguen los métodos (UD04) y los arrays (UD05) esto se escribirá en tres líneas.

Dibuja algo por pantalla con caracteres: un coche, un gato, una casa. Usa *, +, <, #, @

Sobre este ejercicio

No hay solución única, y esa es la gracia. Dos consejos: escríbelo con un bloque de texto """ en lugar de veinte IO.println, y recuerda que la barra invertida \ hay que escribirla doble (\\) porque suelta significa otra cosa.

Bloque 2 · Variables, tipos e identificadores

Sección titulada «Bloque 2 · Variables, tipos e identificadores»

Di cuáles de estos identificadores son válidos en Java y por qué:

mi variable · num_de_cte · ____programa · $alguna · 3tema · cierto? · numeroDeCliente · jose~ · ano · PI · int

Ver solución
Identificador ¿Válido? Motivo
mi variable Lleva un espacio
num_de_cte El guion bajo está permitido
____programa Válido, aunque cuatro guiones no aporten nada
$alguna El $ se permite (se reserva para código generado)
3tema No puede empezar por un dígito
cierto? El ? no es un carácter válido
numeroDeCliente Válido, y además con el convenio correcto
jose~ La ~ no es válida
ano Válido… pero ponle anio o curso y evita el malentendido
PI Válido; por convenio, mayúsculas es una constante
int Es una palabra reservada del lenguaje

Declara una variable para cada dato, con el tipo más pequeño que pueda representarlo, y justifica la elección.

  1. Si un empleado está casado o no.
  2. Un valor máximo que no se puede modificar: 999999.
  3. Día de la semana.
  4. Día del año.
  5. Sexo, con dos valores posibles: 'V' o 'M'.
  6. Milisegundos transcurridos desde el 01/01/1970.
  7. El total de una factura.
  8. La población mundial.
Ver solución
Tipos.java
void main() {
boolean casado = true; // solo cierto o falso
final int MAXIMO = 999999; // no cabe en short (máx. 32.767); final porque no cambia
byte diaSemana = 1; // de 1 a 7, sobra de sobra
short diaAnual = 300; // hasta 366: no cabe en byte, sí en short
char sexo = 'M'; // un único carácter
long milisegundos = 1298332800000L; // desborda int: hace falta long y sufijo L
double totalFactura = 10350.678; // decimales
long poblacion = 6775235741L; // más de 2.147 millones: no cabe en int
IO.println("Casado: " + casado);
IO.println("Máximo: " + MAXIMO);
IO.println("Total factura: %.2f €".formatted(totalFactura));
}

Las dos decisiones que importan: cuándo se sale de int (milisegundos y población desbordan) y cuándo hace falta final (el máximo no debe cambiar).

En un programa real usarías int para el día de la semana y del año sin pensarlo: ahorrar tres bytes no compensa la letra pequeña. La pregunta tiene sentido cuando hablamos de millones de datos.

Este programa tiene seis errores. Encuéntralos y corrígelo.

void main() {
int x = 7
int y = 5;
float f1 = 13.5;
String nombre = 'Carlos';
IO.println("El valor de x es ", x);
IO.println("La división es " + x / y);
IO.println("¿Iguales? " + nombre == "Carlos");
}
Ver solución
  1. int x = 7 — falta el punto y coma.
  2. float f1 = 13.5;13.5 es un double; para un float hace falta 13.5f.
  3. String nombre = 'Carlos'; — las comillas simples son para char; una cadena va con dobles.
  4. IO.println("El valor de x es ", x); — no se separan con coma, se concatena con +.
  5. x / y con dos enteros da 1, no 1.4. Si querías el decimal, fuerza la conversión.
  6. nombre == "Carlos" compara referencias, no contenido. Y encima, por precedencia, se evalúa antes la concatenación: hay que usar nombre.equals("Carlos") entre paréntesis.
Corregido.java
void main() {
int x = 7;
int y = 5;
float f1 = 13.5f;
String nombre = "Carlos";
IO.println("El valor de x es " + x);
IO.println("La división entera es " + (x / y));
IO.println("La división real es " + ((double) x / y));
IO.println("¿Iguales? " + nombre.equals("Carlos"));
}

Declara dos variables enteras con los valores 144 y 999. Muestra su suma, resta, multiplicación, división entera y resto.

Ver solución
Operaciones.java
void main() {
int x = 144;
int y = 999;
IO.println("x = " + x + ", y = " + y);
IO.println("Suma: " + (x + y));
IO.println("Resta: " + (x - y));
IO.println("Producto: " + (x * y));
IO.println("División entera: " + (x / y)); // 0
IO.println("Resto: " + (x % y)); // 144
IO.println("División real: " + ((double) x / y)); // 0.1441...
}

Fíjate en que 144 / 999 da 0, no 0,14. Los paréntesis en las concatenaciones tampoco son opcionales: sin ellos, "Suma: " + x + y escribiría Suma: 144999.

Pide la base imponible y muestra el IVA (21 %) y el total, con dos decimales.

Ver solución
Factura.java
void main() {
final double IVA = 0.21;
double base = Double.parseDouble(IO.readln("Base imponible: "));
double cuota = base * IVA;
double total = base + cuota;
IO.println("Base: %8.2f €".formatted(base));
IO.println("IVA: %8.2f €".formatted(cuota));
IO.println("TOTAL: %8.2f €".formatted(total));
}

Pide una cantidad de segundos y muéstrala como horas, minutos y segundos. Por ejemplo, 3725 → 1 h 2 min 5 s.

Ver solución
Segundos.java
void main() {
int total = Integer.parseInt(IO.readln("Segundos: "));
int horas = total / 3600;
int minutos = (total % 3600) / 60;
int segundos = total % 60;
IO.println(horas + " h " + minutos + " min " + segundos + " s");
}

Este es el ejercicio que enseña para qué sirven de verdad la división entera y el módulo: uno te da los grupos completos y el otro, lo que sobra.

Pide un número entero de hasta cinco cifras y muestra su última cifra y su primera cifra.

Ver solución
Cifras.java
void main() {
int numero = Integer.parseInt(IO.readln("Número (hasta 5 cifras): "));
int ultima = numero % 10;
int primera = numero;
while (primera >= 10) {
primera = primera / 10;
}
IO.println("Última cifra: " + ultima);
IO.println("Primera cifra: " + primera);
}

La última sale con un módulo. La primera, dividiendo entre 10 hasta que solo queda una cifra — y ese bucle es el mismo truco que necesitarás para contar dígitos o detectar capicúas.

Pide dos números y muestra su suma, resta, producto, división, la potencia del primero elevado al segundo, y la raíz cuadrada del primero.

Ver solución
Calculadora.java
void main() {
double x = Double.parseDouble(IO.readln("Primer número: "));
double y = Double.parseDouble(IO.readln("Segundo número: "));
IO.println("x + y = " + (x + y));
IO.println("x - y = " + (x - y));
IO.println("x * y = " + (x * y));
IO.println("x / y = " + (x / y));
IO.println("x ^ y = " + Math.pow(x, y));
IO.println("√x = " + Math.sqrt(x));
}

Math trae hechas las operaciones matemáticas habituales: pow, sqrt, abs, round, max, min, random. No reinventes ninguna.

Pide la base y la altura de un rectángulo y calcula su área y su perímetro.

Ver solución
Rectangulo.java
void main() {
double base = Double.parseDouble(IO.readln("Base: "));
double altura = Double.parseDouble(IO.readln("Altura: "));
IO.println("Área: %.2f".formatted(base * altura));
IO.println("Perímetro: %.2f".formatted(2 * (base + altura)));
}

Pide una hora (horas y minutos) y calcula cuántos segundos faltan para medianoche.

Ver solución
Medianoche.java
void main() {
int horas = Integer.parseInt(IO.readln("Hora (0-23): "));
int minutos = Integer.parseInt(IO.readln("Minutos (0-59): "));
int segundosTranscurridos = horas * 3600 + minutos * 60;
int segundosDelDia = 24 * 3600;
IO.println("Faltan " + (segundosDelDia - segundosTranscurridos) + " segundos");
}

Resuelve ax + b = 0 pidiendo a y b por teclado. Cuidado con el caso en que a valga 0.

Ver solución
PrimerGrado.java
void main() {
double a = Double.parseDouble(IO.readln("Coeficiente a: "));
double b = Double.parseDouble(IO.readln("Coeficiente b: "));
if (a == 0 && b == 0) {
IO.println("Cualquier valor de x es solución");
} else if (a == 0) {
IO.println("La ecuación no tiene solución");
} else {
IO.println("x = " + (-b / a));
}
}

Si divides sin comprobar que a no es cero, con double no obtienes un error: obtienes Infinity o NaN, que es peor, porque el programa sigue como si nada.

Pide dos números y di cuál es mayor, usando el operador ternario.

Ver solución
Mayor.java
void main() {
int a = Integer.parseInt(IO.readln("Primer número: "));
int b = Integer.parseInt(IO.readln("Segundo número: "));
int mayor = (a > b) ? a : b;
IO.println("El mayor es " + mayor);
}

Si son iguales, este código dice que el mayor es b. ¿Es aceptable? Depende del enunciado — y esa es justo la clase de pregunta que hay que hacer en la fase de análisis.

Pide una hora (solo la hora, sin minutos) y saluda: buenos días de 6 a 12, buenas tardes de 13 a 20, y buenas noches de 21 a 5.

Ver solución
Saludo.java
void main() {
int hora = Integer.parseInt(IO.readln("¿Qué hora es? (0-23) "));
if (hora < 0 || hora > 23) {
IO.println("Esa hora no existe");
} else if (hora >= 6 && hora <= 12) {
IO.println("Buenos días");
} else if (hora >= 13 && hora <= 20) {
IO.println("Buenas tardes");
} else {
IO.println("Buenas noches");
}
}

El tramo de noche es el interesante: va de 21 a 5 pasando por medianoche, así que no se puede escribir como un intervalo normal. Al dejarlo en el else final, el problema desaparece.

Pide una nota del 0 al 10 y muestra la calificación: insuficiente, suficiente, bien, notable o sobresaliente.

Ver solución
Boletin.java
void main() {
double nota = Double.parseDouble(IO.readln("Nota (0-10): "));
String calificacion;
if (nota < 0 || nota > 10) {
calificacion = "Nota no válida";
} else if (nota < 5) {
calificacion = "Insuficiente";
} else if (nota < 6) {
calificacion = "Suficiente";
} else if (nota < 7) {
calificacion = "Bien";
} else if (nota < 9) {
calificacion = "Notable";
} else {
calificacion = "Sobresaliente";
}
IO.println(calificacion);
}

Aquí el switch no sirve: no comparamos con valores sueltos, sino con intervalos. Ese es el criterio para elegir entre uno y otro.

Pide el importe de una compra y aplica el descuento correspondiente: menos de 200 €, ninguno; de 200 a 500, un 5 %; de 501 a 1000, un 10 %; más de 1000, un 15 %. Muestra el descuento aplicado y el total.

Ver solución
Descuentos.java
void main() {
double importe = Double.parseDouble(IO.readln("Importe de la compra: "));
double descuento;
if (importe < 200) {
descuento = 0;
} else if (importe <= 500) {
descuento = 0.05;
} else if (importe <= 1000) {
descuento = 0.10;
} else {
descuento = 0.15;
}
double rebaja = importe * descuento;
IO.println("Descuento: %.0f%% (%.2f €)".formatted(descuento * 100, rebaja));
IO.println("Total a pagar: %.2f €".formatted(importe - rebaja));
}

Fíjate en el enunciado: dice «de 501 a 1000», pero ¿y una compra de 500,40 €? El enunciado se ha escrito pensando en euros enteros. Usando <= en cascada, ese hueco desaparece.

Para escribir un % literal en una cadena con formato hay que doblarlo: %%.

Pide un año y di si es bisiesto. Un año es bisiesto si es divisible entre 4, salvo que sea divisible entre 100 y no entre 400.

Ver solución
Bisiesto.java
void main() {
int anio = Integer.parseInt(IO.readln("Año: "));
boolean bisiesto = (anio % 4 == 0 && anio % 100 != 0) || (anio % 400 == 0);
IO.println(anio + (bisiesto ? " es bisiesto" : " no es bisiesto"));
}

Toda la regla cabe en una expresión booleana. Pruébalo con 2024 (sí), 1900 (no) y 2000 (sí): esos tres casos son los que distinguen una solución correcta de una que solo mira el múltiplo de 4.

Pide un número del 1 al 7 y muestra el nombre del día correspondiente. Usa switch.

Ver solución
DiaSemana.java
void main() {
int dia = Integer.parseInt(IO.readln("Día (1-7): "));
String nombre = switch (dia) {
case 1 -> "Lunes";
case 2 -> "Martes";
case 3 -> "Miércoles";
case 4 -> "Jueves";
case 5 -> "Viernes";
case 6 -> "Sábado";
case 7 -> "Domingo";
default -> "Día no válido";
};
IO.println(nombre);
}

Resuelve ax² + bx + c = 0. Contempla los tres casos según el discriminante: dos soluciones, una o ninguna real.

Ver solución
SegundoGrado.java
void main() {
double a = Double.parseDouble(IO.readln("Coeficiente a: "));
double b = Double.parseDouble(IO.readln("Coeficiente b: "));
double c = Double.parseDouble(IO.readln("Coeficiente c: "));
if (a == 0) {
IO.println("No es una ecuación de segundo grado");
return;
}
double discriminante = b * b - 4 * a * c;
if (discriminante > 0) {
double x1 = (-b + Math.sqrt(discriminante)) / (2 * a);
double x2 = (-b - Math.sqrt(discriminante)) / (2 * a);
IO.println("Dos soluciones: x1 = %.4f, x2 = %.4f".formatted(x1, x2));
} else if (discriminante == 0) {
IO.println("Una solución: x = %.4f".formatted(-b / (2 * a)));
} else {
IO.println("No tiene soluciones reales");
}
}

return dentro de main termina el programa ahí mismo. Es la forma más limpia de salir cuando los datos no son válidos y no tiene sentido seguir.

Muestra los números del 320 al 160, de 20 en 20 hacia atrás. Hazlo tres veces: con for, con while y con do-while.

Ver solución
CuentaAtras.java
void main() {
IO.println("Con for:");
for (int i = 320; i >= 160; i -= 20) {
IO.print(i + " ");
}
IO.println();
IO.println("Con while:");
int j = 320;
while (j >= 160) {
IO.print(j + " ");
j -= 20;
}
IO.println();
IO.println("Con do-while:");
int k = 320;
do {
IO.print(k + " ");
k -= 20;
} while (k >= 160);
IO.println();
}

Los tres hacen lo mismo. La diferencia está en dónde vive el contador: el for lo tiene todo junto en una línea, y por eso es el que menos se olvida de actualizar.

La combinación es un número de cuatro cifras. Pídela hasta cuatro veces. Si acierta, «La caja fuerte se ha abierto satisfactoriamente»; si agota los intentos, avísale de que se ha bloqueado.

Ver solución
CajaFuerte.java
void main() {
final String COMBINACION = "2468";
final int INTENTOS = 4;
boolean abierta = false;
int intento = 0;
while (intento < INTENTOS && !abierta) {
String clave = IO.readln("Combinación: ");
if (clave.equals(COMBINACION)) {
abierta = true;
} else {
intento++;
IO.println("Lo siento, esa no es la combinación. Te quedan "
+ (INTENTOS - intento) + " intentos.");
}
}
if (abierta) {
IO.println("La caja fuerte se ha abierto satisfactoriamente");
} else {
IO.println("Caja bloqueada");
}
}

Con la variable abierta en la condición, el bucle termina solo y no hacen falta break. Es más largo de escribir y mucho más fácil de seguir.

Pide números positivos y calcula su media. El usuario termina metiendo un número negativo, que no cuenta.

Ver solución
Media.java
void main() {
double suma = 0;
int cantidad = 0;
double numero = Double.parseDouble(IO.readln("Número (negativo para terminar): "));
while (numero >= 0) {
suma += numero;
cantidad++;
numero = Double.parseDouble(IO.readln("Número (negativo para terminar): "));
}
if (cantidad == 0) {
IO.println("No has introducido ningún número");
} else {
IO.println("Has introducido %d números. Media: %.2f".formatted(cantidad, suma / cantidad));
}
}

Dos cosas que suspenden este ejercicio: contar el número negativo dentro de la media, y dividir entre cero cuando el usuario sale a la primera.

Pide un número entero positivo y calcula su factorial. Recuerda que 5! = 5 × 4 × 3 × 2 × 1.

Ver solución
Factorial.java
void main() {
int n = Integer.parseInt(IO.readln("Número: "));
if (n < 0) {
IO.println("El factorial no está definido para negativos");
return;
}
long factorial = 1;
for (int i = 2; i <= n; i++) {
factorial *= i;
}
IO.println(n + "! = " + factorial);
}

long y no int: el factorial crece disparado y a partir de 13 ya no cabe en un int. Pruébalo con 20 y con 21, y verás que ni siquiera long aguanta mucho.

Pide un número y di si es primo.

Ver solución
Primo.java
void main() {
int n = Integer.parseInt(IO.readln("Número: "));
boolean primo = n > 1;
for (int divisor = 2; divisor <= Math.sqrt(n); divisor++) {
if (n % divisor == 0) {
primo = false;
break;
}
}
IO.println(n + (primo ? " es primo" : " no es primo"));
}

No hace falta probar todos los divisores hasta n: si un número tiene un divisor mayor que su raíz cuadrada, necesariamente tiene otro menor, que ya habríamos encontrado. Con 1.000.000 la diferencia es de un millón de vueltas a mil.

Pide un número n y muestra los n primeros términos de la serie de Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13…

Ver solución
Fibonacci.java
void main() {
int n = Integer.parseInt(IO.readln("¿Cuántos términos? "));
long anterior = 0;
long actual = 1;
for (int i = 1; i <= n; i++) {
IO.print(anterior + " ");
long siguiente = anterior + actual;
anterior = actual;
actual = siguiente;
}
IO.println();
}

La clave es la variable siguiente: sin ella, al asignar anterior = actual pierdes el valor que necesitabas justo después.

Pide la altura y el carácter, y dibuja una pirámide rellena.

Ver solución
Piramide.java
void main() {
int altura = Integer.parseInt(IO.readln("Altura: "));
String simbolo = IO.readln("Carácter: ");
for (int fila = 1; fila <= altura; fila++) {
for (int espacio = 1; espacio <= altura - fila; espacio++) {
IO.print(" ");
}
for (int i = 1; i <= 2 * fila - 1; i++) {
IO.print(simbolo);
}
IO.println();
}
}

Dos bucles anidados dentro del principal: uno pinta los espacios que centran la figura y otro los símbolos. La fórmula 2 * fila - 1 da la serie 1, 3, 5, 7…, que es lo que hace que quede triangular.

Pide un número de cinco cifras y di si es capicúa (se lee igual del derecho que del revés).

Ver solución
Capicua.java
void main() {
int numero = Integer.parseInt(IO.readln("Número: "));
int original = numero;
int alReves = 0;
while (numero > 0) {
alReves = alReves * 10 + numero % 10;
numero /= 10;
}
IO.println(original + (original == alReves ? " es capicúa" : " no es capicúa"));
}

Le vamos quitando la última cifra al número (% 10) y construyendo el número al revés (* 10 +). Después basta comparar. Guarda el valor original antes del bucle: al terminar, numero vale 0.

Escribe un menú con cuatro opciones (vender, consultar, administrar, salir) que se repita hasta que el usuario elija salir. Si mete una opción que no existe, avisa y vuelve a mostrarlo.

Ver solución
Menu.java
void main() {
int opcion;
do {
IO.println("""
=== AUDITORIO DE MARTOS ===
1. Vender entradas
2. Consultar evento
3. Administración
4. Salir
""");
opcion = Integer.parseInt(IO.readln("Elige una opción: "));
switch (opcion) {
case 1 -> IO.println("Vendiendo entradas…");
case 2 -> IO.println("Consultando evento…");
case 3 -> IO.println("Entrando en administración…");
case 4 -> IO.println("Hasta luego");
default -> IO.println("Esa opción no existe");
}
} while (opcion != 4);
}

Este ejercicio es el esqueleto de la práctica de la unidad: si lo tienes claro, la práctica es ir rellenando cada case.

© 2026 Carlos Barroso · Contenido bajo CC BY-NC-SA 4.0