Saltar a contenido

7.2.-Entrada/Salida estandar

7.2 Lectura y escritura en consola

Después de comprender en 7.1 qué es la entrada/salida, ahora toca trabajar con el caso más cercano y habitual: la consola.

Este apartado está directamente relacionado con el resultado de aprendizaje 5, especialmente con los criterios que piden:
- a) usar la consola para realizar operaciones de entrada y salida.
- b) aplicar formatos en la visualización de la información.
- c) reconocer posibilidades de E/S del lenguaje y sus librerías.

La idea es sencilla: un programa de consola muestra mensajes, pide datos y responde en función de lo que introduce la persona usuaria. Aunque parezca básico, aquí se apoyan muchas prácticas posteriores: validación de datos, mensajes claros, formato de salida y separación entre lógica y presentación.

Qué vas a aprender en este tema

  • Escribir mensajes en la salida estándar y de error.
  • Leer datos desde teclado con Kotlin.
  • Validar conversiones básicas de texto a números.
  • Aplicar formato a la salida para que sea más clara y útil.

1. La consola como canal de entrada y salida

En una aplicación de consola trabajamos, como mínimo, con tres canales:

  • entrada estándar, normalmente el teclado;
  • salida estándar, normalmente la consola;
  • salida de error, usada para avisos o mensajes de fallo.

En la JVM estos canales se representan mediante:

  • System.in
  • System.out
  • System.err

En Kotlin no solemos trabajar directamente con ellos todo el tiempo, porque el lenguaje ofrece funciones más cómodas para el caso habitual de consola.

Idea clave

En este tema no estamos guardando todavía información en ficheros. Aquí nos centramos en la comunicación inmediata entre la persona usuaria y el programa.

2. Escribir información en consola

Las funciones más habituales para mostrar texto son print() y println().

  • print() escribe sin salto de línea final.
  • println() escribe y añade un salto de línea al final.
fun main() {
    print("Hola")
    print(" ")
    println("mundo")
    println("Segunda línea")
}

Salida:

Hola mundo
Segunda línea

Si necesitas un salto de línea dentro del propio texto, puedes usar \n:

println("Línea 1\nLínea 2")

2.1. Plantillas de cadenas

En Kotlin, la forma más cómoda de mezclar texto con variables suele ser la interpolación:

val nombre = "Alicia"
val nota = 8.5

println("Alumno: $nombre")
println("Nota final: $nota")
println("El doble de la nota es ${nota * 2}")

Esta técnica hace el código más legible que concatenar muchas cadenas con +.

2.2. Salida de error

Cuando quieres diferenciar un mensaje correcto de uno problemático, puedes usar System.err:

System.err.println("No se ha podido leer la edad")

No siempre será visible de forma distinta en el terminal, pero conceptualmente es importante porque separa la salida normal de los errores.

3. Leer datos desde teclado

En Kotlin actual, para leer una línea completa desde teclado es habitual usar readln() o readlnOrNull().

  • readln() devuelve un String.
  • readlnOrNull() devuelve String? y permite contemplar el caso en que no haya datos.

3.1. Leer texto

fun main() {
    print("Introduce tu nombre: ")
    val nombre = readln()
    println("Hola, $nombre")
}

Este ejemplo es suficiente cuando esperamos una línea de texto y damos por hecho que la entrada estará disponible.

3.2. Leer números con seguridad

El teclado siempre entrega texto. Si queremos obtener un número, primero leemos una cadena y después la convertimos.

La forma más segura para empezar no es toInt(), sino toIntOrNull():

fun main() {
    print("Introduce tu edad: ")
    val edad = readln().toIntOrNull()

    if (edad != null) {
        println("Tienes $edad años")
    } else {
        System.err.println("La edad introducida no es válida")
    }
}

También existen:

  • toDoubleOrNull()
  • toFloatOrNull()
  • toLongOrNull()

3.3. Evita !! al leer datos

Es frecuente encontrar ejemplos como este:

val numero = readln().toInt()

o, en ejemplos antiguos:

val numero = readLine()!!.toInt()

Funcionan si la entrada es correcta, pero fallan con facilidad cuando la persona usuaria introduce algo inesperado. Para aplicaciones de aprendizaje y para programas robustos, conviene validar.

Error frecuente

Si conviertes directamente con toInt() y la entrada no es un entero válido, obtendrás una excepción en tiempo de ejecución.

3.4. Repetir la petición hasta obtener un dato válido

Una mejora muy habitual consiste en seguir preguntando hasta recibir una entrada correcta:

fun main() {
    var cantidad: Int? = null

    while (cantidad == null) {
        print("Introduce una cantidad entera: ")
        cantidad = readln().toIntOrNull()

        if (cantidad == null) {
            System.err.println("Dato no válido. Inténtalo de nuevo.")
        }
    }

    println("Cantidad aceptada: $cantidad")
}

Este patrón aparece mucho en programas de consola y en actividades de clase.

4. Formato de salida

Una cosa es que un programa funcione y otra que su salida sea clara. El criterio de evaluación sobre formato no consiste solo en “que imprima algo”, sino en que la información se vea bien y resulte fácil de interpretar.

4.1. Cuándo basta con interpolación

Para mensajes sencillos, la interpolación suele ser suficiente:

val producto = "Teclado"
val precio = 19.95

println("Producto: $producto")
println("Precio: $precio €")

4.2. Cuándo usar format

Si necesitas controlar decimales, anchos de columna o alineación, es más útil usar format:

val nombre = "Marta"
val nota = 7.456

println("Alumno: %s | Nota: %.2f".format(nombre, nota))

Salida:

Alumno: Marta | Nota: 7.46

Algunos especificadores habituales son:

Formato Uso habitual
%s texto
%d entero
%.2f decimal con 2 cifras
%n salto de línea

4.3. Ejemplo de tabla sencilla

val articulos = listOf(
    "Cuaderno" to 2.5,
    "Bolígrafo" to 1.2,
    "Mochila" to 24.95
)

println("%-12s | %8s".format("Artículo", "Precio"))
println("-----------------------------")

for ((articulo, precio) in articulos) {
    println("%-12s | %8.2f €".format(articulo, precio))
}

Salida:

Artículo     |   Precio
-----------------------------
Cuaderno     |     2.50 €
Bolígrafo    |     1.20 €
Mochila      |    24.95 €

5. Ejemplo integrador

El siguiente programa combina lectura por teclado, validación y formato de salida:

fun main() {
    print("Nombre del producto: ")
    val producto = readln()

    print("Unidades: ")
    val unidades = readln().toIntOrNull()

    print("Precio unitario: ")
    val precio = readln().toDoubleOrNull()

    if (unidades == null || precio == null) {
        System.err.println("No se puede generar el ticket porque hay datos no válidos.")
        return
    }

    val total = unidades * precio

    println()
    println("Ticket de compra")
    println("------------------------------")
    println("Producto: $producto")
    println("Unidades: %d".format(unidades))
    println("Precio/u: %.2f €".format(precio))
    println("Total: %.2f €".format(total))
}

Este ejemplo ya refleja una situación realista de RA5:

  • se lee información desde teclado;
  • se muestra información en consola;
  • se valida la entrada;
  • y se cuida el formato de salida.

6. Buenas prácticas

Cuando trabajes con consola y teclado, intenta seguir estas ideas:

  • muestra mensajes claros antes de pedir cada dato;
  • valida los números antes de usarlos;
  • no abuses de !!;
  • usa System.err para errores o avisos;
  • separa, cuando el programa crezca, la lógica del cálculo y la presentación en consola.

Ampliación

Si necesitas más detalle sobre lectura avanzada, Scanner o variantes históricas como readLine(), consulta 7.2.1. Consola y teclado: ampliación.

7. Resumen

En este tema has visto que:

  • la consola permite interactuar con la persona usuaria de forma inmediata;
  • print() y println() sirven para mostrar información;
  • readln() y readlnOrNull() permiten leer desde teclado;
  • la validación con toIntOrNull() y similares evita muchos errores;
  • el formato de salida mejora la claridad y cumple con el criterio de evaluación asociado.

Con esta base ya puedes crear programas sencillos de consola que pidan datos, los validen y muestren resultados de forma clara.

Fuentes