Saltar al contenido principal

Proyecto: gestor de datos en consola

Vas a construir un gestor de alumnos y notas. La aplicación mantendrá datos durante su ejecución, ofrecerá un menú y separará cada operación en un método. No necesitaremos clases propias, colecciones ni ficheros.

Contexto​

Una profesora quiere registrar hasta veinte alumnos, consultar sus notas, actualizarlas y obtener un resumen del grupo. Los datos desaparecen al cerrar el programa; la persistencia pertenece a otro nivel.

Requisitos funcionales​

El programa debe permitir:

  1. añadir un alumno y una nota entre 0 y 10;
  2. listar los alumnos registrados;
  3. buscar un alumno por nombre sin distinguir mayúsculas;
  4. actualizar su nota;
  5. mostrar cantidad, promedio, nota máxima y aprobados;
  6. rechazar nombres vacíos, notas fuera de rango y duplicados;
  7. avisar cuando no hay datos o no se encuentra un nombre;
  8. salir desde el menú.

Puedes asumir que, cuando se pide un número, la persona escribe un dato numérico. La validación mediante excepciones queda fuera de Java 1.

Diseño por fases​

Construye y prueba en este orden:

  1. crea el menú repetitivo;
  2. registra un alumno en arrays;
  3. lista solo las posiciones ocupadas;
  4. extrae la búsqueda a un método;
  5. reutiliza la búsqueda para actualizar;
  6. calcula las estadísticas;
  7. añade validaciones y mensajes.

Esta secuencia permite comprobar cada capacidad antes de sumar la siguiente.

Modelo de datos​

Usaremos dos arrays paralelos y un contador:

String[] nombres = new String[20];
double[] notas = new double[20];
int cantidad = 0;

La posición i de ambos arrays pertenece al mismo alumno. Solo las posiciones desde 0 hasta cantidad - 1 contienen registros válidos.

índice      0        1       2
nombres "Ana" "Luis" "Marta"
notas 8.5 6.0 9.0
cantidad = 3

El tamaño fijo es una decisión consciente de Java 1. Las colecciones dinámicas se estudiarán más adelante.

Menú​

1. Añadir alumno
2. Listar alumnos
3. Buscar alumno
4. Actualizar nota
5. Mostrar estadísticas
0. Salir

do while garantiza que el menú aparezca al menos una vez. switch dirige cada opción.

Métodos sugeridos​

  • mostrarMenu() presenta opciones.
  • anadirAlumno(...) valida y guarda un nuevo registro.
  • listar(...) recorre registros ocupados.
  • buscarDesdeConsola(...) pide un nombre y presenta el resultado.
  • buscarPosicion(...) devuelve el índice o -1.
  • actualizarNota(...) valida y modifica una posición.
  • notaValida(...) centraliza la regla 0..10.
  • mostrarEstadisticas(...) calcula agregaciones.

anadirAlumno(...) realiza el alta y devuelve la nueva cantidad. main asigna ese resultado a cantidad, de modo que la actualización del contador queda explícita.

Implementación completa​

Guarda el archivo como GestorNotas.java:

import java.util.Scanner;

public class GestorNotas {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
String[] nombres = new String[20];
double[] notas = new double[20];
int cantidad = 0;
int opcion;

do {
mostrarMenu();
opcion = entrada.nextInt();
entrada.nextLine();

switch (opcion) {
case 1:
cantidad = anadirAlumno(entrada, nombres, notas, cantidad);
break;
case 2:
listar(nombres, notas, cantidad);
break;
case 3:
buscarDesdeConsola(entrada, nombres, notas, cantidad);
break;
case 4:
actualizarNota(entrada, nombres, notas, cantidad);
break;
case 5:
mostrarEstadisticas(notas, cantidad);
break;
case 0:
System.out.println("Hasta pronto");
break;
default:
System.out.println("Opción no válida");
}
} while (opcion != 0);

entrada.close();
}

public static void mostrarMenu() {
System.out.println();
System.out.println("1. Añadir alumno");
System.out.println("2. Listar alumnos");
System.out.println("3. Buscar alumno");
System.out.println("4. Actualizar nota");
System.out.println("5. Mostrar estadísticas");
System.out.println("0. Salir");
System.out.print("Opción: ");
}

public static int anadirAlumno(Scanner entrada, String[] nombres,
double[] notas, int cantidad) {
if (cantidad == nombres.length) {
System.out.println("No quedan posiciones libres");
return cantidad;
}

System.out.print("Nombre: ");
String nombre = entrada.nextLine().strip();

if (nombre.length() == 0) {
System.out.println("El nombre no puede estar vacío");
return cantidad;
}

if (buscarPosicion(nombres, cantidad, nombre) != -1) {
System.out.println("Ese alumno ya existe");
return cantidad;
}

System.out.print("Nota: ");
double nota = entrada.nextDouble();
entrada.nextLine();

if (!notaValida(nota)) {
System.out.println("La nota debe estar entre 0 y 10");
return cantidad;
}

nombres[cantidad] = nombre;
notas[cantidad] = nota;
System.out.println("Alumno añadido");
return cantidad + 1;
}

public static void listar(String[] nombres, double[] notas, int cantidad) {
if (cantidad == 0) {
System.out.println("No hay alumnos registrados");
return;
}

for (int posicion = 0; posicion < cantidad; posicion++) {
System.out.println((posicion + 1) + ". " + nombres[posicion]
+ " - " + notas[posicion]);
}
}

public static void buscarDesdeConsola(Scanner entrada, String[] nombres,
double[] notas, int cantidad) {
System.out.print("Nombre que buscas: ");
String nombre = entrada.nextLine().strip();
int posicion = buscarPosicion(nombres, cantidad, nombre);

if (posicion == -1) {
System.out.println("Alumno no encontrado");
} else {
System.out.println(nombres[posicion] + " - " + notas[posicion]);
}
}

public static int buscarPosicion(String[] nombres, int cantidad,
String buscado) {
for (int posicion = 0; posicion < cantidad; posicion++) {
if (nombres[posicion].equalsIgnoreCase(buscado)) {
return posicion;
}
}
return -1;
}

public static void actualizarNota(Scanner entrada, String[] nombres,
double[] notas, int cantidad) {
System.out.print("Nombre que quieres actualizar: ");
String nombre = entrada.nextLine().strip();
int posicion = buscarPosicion(nombres, cantidad, nombre);

if (posicion == -1) {
System.out.println("Alumno no encontrado");
return;
}

System.out.print("Nueva nota: ");
double nuevaNota = entrada.nextDouble();
entrada.nextLine();

if (!notaValida(nuevaNota)) {
System.out.println("La nota debe estar entre 0 y 10");
return;
}

notas[posicion] = nuevaNota;
System.out.println("Nota actualizada");
}

public static boolean notaValida(double nota) {
return nota >= 0 && nota <= 10;
}

public static void mostrarEstadisticas(double[] notas, int cantidad) {
if (cantidad == 0) {
System.out.println("No hay datos para calcular estadísticas");
return;
}

double suma = 0;
double maxima = notas[0];
int aprobados = 0;

for (int posicion = 0; posicion < cantidad; posicion++) {
double nota = notas[posicion];
suma += nota;

if (nota > maxima) {
maxima = nota;
}
if (nota >= 5) {
aprobados++;
}
}

double promedio = suma / cantidad;
System.out.println("Alumnos: " + cantidad);
System.out.println("Promedio: " + promedio);
System.out.println("Nota máxima: " + maxima);
System.out.println("Aprobados: " + aprobados);
}
}

Decisiones de diseño​

Recorrer solo los datos ocupados​

Los arrays tienen veinte posiciones, pero cantidad indica cuántas contienen alumnos. Todos los recorridos terminan en cantidad, no en nombres.length, para evitar posiciones vacías.

Una búsqueda reutilizable​

buscarPosicion se usa al impedir duplicados, consultar y actualizar. Devuelve -1 si no encuentra el nombre, igual que otras operaciones de búsqueda vistas en el curso.

Arrays paralelos​

El mismo índice relaciona nombre y nota. No es la solución definitiva para aplicaciones grandes, pero permite cerrar Java 1 sin adelantar clases propias ni objetos de dominio.

Validación por condiciones​

El nombre, el rango, la capacidad y los duplicados se comprueban con condiciones. No capturamos entradas de tipo incorrecto porque el tratamiento completo de excepciones queda fuera del curso.

Métodos static​

Se usan para poder llamarlos desde main con los conocimientos actuales. No implican que todos los programas futuros deban diseñarse así.

Casos de prueba manuales​

Ejecuta al menos estos recorridos:

CasoPasosResultado esperado
Sin datoslistar, estadísticasdos avisos; no hay accesos fuera del array
Alta válidaAna, 8.5aparece al listar y buscar ana
Duplicadovolver a añadir ANAse rechaza sin aumentar la cantidad
Nombre vacíointroducir espaciosse rechaza
Nota inválidaLuis, 12se rechaza y Luis no aparece
Actualizacióncambiar Ana a 9la lista y estadísticas usan 9
No encontradobuscar Martamuestra aviso
Varias notasAna 9, Luis 6, Marta 4promedio 6.333..., máxima 9, dos aprobados
Opción desconocidaelegir 8aviso y el menú continúa
Salidaelegir 0mensaje final y termina

Ampliaciones compatibles con Java 1​

Cuando la versión base funcione, puedes:

  • contar suspensos;
  • mostrar el alumno con nota máxima conservando su posición;
  • listar solo notas por encima de un límite;
  • permitir eliminar un registro desplazando las posiciones posteriores;
  • guardar varias notas por alumno en una matriz y calcular promedios por fila;
  • añadir una opción que busque coincidencias parciales con contains.

Todas estas ampliaciones caben en Java 1. No añadas clases propias, ArrayList, ficheros ni excepciones completas todavía.

Cierre de Java 1​

Has pasado de programas lineales con decisiones a aplicaciones que repiten procesos, separan responsabilidades en métodos y trabajan con texto, arrays y matrices. El siguiente nivel podrá sustituir los arrays paralelos por modelos con clases y objetos; esa nueva forma de organizar el programa merece estudiarse por separado.