7.A Consola: entrada y salida estándar¶
Cuando un programa se ejecuta en una terminal, el sistema le da tres canales de texto, llamados flujos estándar:
| Flujo | Nombre | Para qué sirve | Por defecto |
|---|---|---|---|
stdin |
Entrada estándar | Lo que el programa recibe | El teclado |
stdout |
Salida estándar | Los resultados normales | La pantalla |
stderr |
Salida de error | Los avisos y errores | La pantalla |
Los dos de salida van a la pantalla, pero son canales distintos, y esa diferencia permite separar los resultados de los mensajes de error.
Mostrar datos con formato¶
import java.util.List;
import java.util.Locale;
public class Cons1 {
record Equipo(String nombre, int puntos, int diferencia) {}
public static void main(String[] args) {
List<Equipo> equipos = List.of(new Equipo("Águilas", 45, 12), new Equipo("Lobos", 41, 5), new Equipo("Tigres", 38, -2));
System.out.println(String.format("%-12s%5s%6s", "Equipo", "Pts", "Dif"));
System.out.println("-".repeat(23));
int total = 0;
for (Equipo e : equipos) {
System.out.println(String.format("%-12s%5d%+6d", e.nombre(), e.puntos(), e.diferencia()));
total += e.puntos();
}
System.out.println("Media de puntos: " + String.format(Locale.ROOT, "%.2f", (double) total / equipos.size()));
System.err.println("Aviso: datos de ejemplo, no oficiales");
System.out.println("Fin del informe");
}
}
Salida:
Equipo Pts Dif
-----------------------
Águilas 45 +12
Lobos 41 +5
Tigres 38 -2
Media de puntos: 41.33
Fin del informe
Qué conviene aprender de este ejemplo:
- Columnas alineadas. Se reserva un ancho fijo para cada columna: el texto a la izquierda y los números a la derecha. Sin eso, las columnas quedan descuadradas.
- Decimales fijos. La media sale con dos decimales aunque el cálculo dé muchos más.
- El aviso va por otro canal. Verás que la línea «Aviso: datos de ejemplo, no oficiales» no aparece en el recuadro de arriba: se escribe en
stderr, no enstdout. En una terminal sí se vería.
| Necesito... | En Java |
|---|---|
| Alinear a la izquierda | %-12s |
| Alinear a la derecha | %5d |
| Decimales fijos | %.2f |
| Repetir un texto | "-".repeat(23) |
| Mostrar sin salto de línea | System.out.print("texto") |
| Con signo | %+d |
String.format usa la configuración regional del equipo: en un Windows en español, %.2f escribe 41,33 (con coma). Para que siempre salga con punto, pasa Locale.ROOT como primer argumento (String.format(Locale.ROOT, "%.2f", x)), como hace el ejemplo.
Salida estándar y salida de error¶
Separarlas sirve para que un programa pueda guardar los resultados en un archivo sin mezclarlos con los errores. En una terminal, el operador > redirige la salida normal y 2> la de error:
programa > resultados.txt 2> errores.txt
Con el ejemplo anterior, resultados.txt contendría la tabla y la media y errores.txt solo el aviso:
java Cons1.java > resultados.txt 2> errores.txt
Para dar entrada desde un archivo en lugar del teclado se usa < (programa < entrada.txt), y para encadenar programas, la tubería |.
Leer datos¶
Se lee con un Scanner sobre System.in: nextLine() lee una línea completa y hasNextLine() dice si queda alguna. Un fallo clásico: nextInt() no consume el salto de línea, así que un nextLine() posterior devuelve una cadena vacía. Lo más seguro es leer siempre con nextLine() y convertir después con Integer.parseInt. La salida de error es System.err.
import java.util.Scanner;
public class Cons2 {
public static void main(String[] args) {
Scanner teclado = new Scanner(System.in);
System.out.println("Escribe líneas (una vacía para terminar):");
int lineas = 0;
int palabras = 0;
while (teclado.hasNextLine()) {
String linea = teclado.nextLine();
if (linea.isEmpty()) {
break;
}
lineas++;
palabras += linea.trim().split("\\s+").length;
}
System.out.println("Líneas: " + lineas);
System.out.println("Palabras: " + palabras);
}
}
Este programa lee líneas hasta encontrar una vacía (o hasta que se acabe la entrada). Si se le escribe hola mundo, esto es una prueba y una línea vacía, muestra:
Escribe líneas (una vacía para terminar):
Líneas: 2
Palabras: 6
Una entrada del usuario es siempre texto: si necesitas un número hay que convertirlo y prever que falle (ver el patrón de «pedir hasta que sea válido» en 2.3 Excepciones).
Errores frecuentes¶
| Error | Cómo evitarlo |
|---|---|
| Columnas descuadradas | Fijar un ancho para cada columna y alinear números a la derecha |
| Mezclar resultados y errores en la misma salida | Escribir los avisos en stderr |
| Dar por hecho que siempre hay una línea más que leer | Comprobar el fin de la entrada (null, hasNextLine, EOFError) |
| Usar el número leído sin convertirlo ni validarlo | Convertir dentro de un try y volver a pedir |
| Decimales con coma en unas máquinas y con punto en otras | Fijar la configuración regional al formatear (en Java y Kotlin) |
Para practicar¶
Haz los ejercicios de U7.1 · Consola. Para ver cómo se escribe en otro lenguaje: Pasar de uno a otro.