El argumento args de main en Java

En esta entrada veremos para qué sirve el parámetro args del método main.
El parámetro args es un array de Strings que debe aparecer obligatoriamente como argumento del método main en un programa Java.
public static void main(String[] args){
    
}
Aunque se le suele dar el nombre args, no es obligatorio que este parámetro se llame así, podemos darle el nombre que queramos. Por ejemplo sería valido un método main escrito así:
public static void main(String[] argumentos){
    
}
Para qué sirve el array String [] args de main?
Trabajando con un entorno de desarrollo a menudo nos olvidamos de que un programa java se puede ejecutar desde la línea de comandos del sistema operativo con la orden:
C:\> java nombrePrograma
Además, mediante esta orden, podemos enviar valores al programa.
Por ejemplo, si tenemos un programa que se llama ordenar que ordena 5 números enteros, pero en lugar de leerlos por teclado los números se le pasan al programa como argumentos, este programa lo ejecutaríamos así: 
C:\> java ordenar 4 6 3 7 1
Los valores que se envían se deben escribir a continuación del nombre del programa y separados por un espacio en blanco.
El array array args que aparece como argumento del método main es el encargado de recoger y almacenar estos valores.  







Como args es un array de Strings contendrá cada uno de estos valores como un String:
Contenido del Arrays args:





La propiedad length del array args (args.length) contiene el número de valores enviados al programa.
Siempre que trabajemos con valores recibidos desde la línea de comandos debemos controlar el número de valores recibidos para evitar que se produzcan errores al procesar el array.
Ejemplo.
Programa llamado saludo que recibe desde la línea de comandos del sistema operativo un nombre de persona y lo muestra por pantalla.
public class saludo{
    public static void main(String[] args) {
        if (args.length > 1) { //si hay más de 1 parámetro
            System.out.println("Hay demasiados parámetros. Debe escribir: saludo nombrePersona");
        } else if (args.length == 0) { //si no hay parámetros      
            System.out.println("Falta el nombre de la persona");                                                  
        } else {
            System.out.println("Buenos Días " + args[0]);
        }
    }
}
Para ejecutarlo se debe escribir en la línea de comandos:
>java saludo nombreCualquiera
Por ejemplo:
> java saludo Juan
La salida del programa sería en este caso:
Buenos Días Juan
Debemos tener en cuenta que todos los valores que se envían a main desde la línea de comandos son de tipo String. Si uno de los parámetros introducido en la línea de comandos es un número, el programa lo tratará como un String, por lo que para tratarlo como número y poder operar matemáticamente con él habrá que hacer la conversión al tipo numérico adecuado.

Ejemplo
El siguiente programa llamado longcir recibe desde la línea de comandos el valor del radio de una circunferencia y calcula y muestra la longitud de la circunferencia.
public class longcir {
    public static void main(String[] args) {
        double radio;
        if (args.length > 1) { //si hay más de 1 parámetro
            System.out.println("Hay demasiados parámetros. Debe escribir: longcir valorRadio");
        } else if (args.length == 0) { //si no hay parámetros      
            System.out.println("Falta el valor del radio");
        } else {
            radio = Double.parseDouble(args[0]); //Se convierte el argumento a double 
            System.out.println("Longitud de la circunferencia: " + 2 * Math.PI * radio);                          
        }
    }
}
Ejemplo
Programa echo que muestra los argumentos introducidos en la línea de comandos.
public class echo {
    public static void main(String[] args) {
        int i;
        for (i = 0; i < args.length; i++) {
            System.out.print(args[i]+ " ");                                                                       
        }
        System.out.println();
    }
}
Enviar valores a main en Netbeans
Si estamos utilizando un IDE podemos ejecutar programas que reciben valores desde la línea de comandos desde el propio IDE sin necesidad de ejecutarlo desde la línea de comandos.
En NetBeans se realiza de la siguiente forma:
Botón derecho sobre el proyecto y seleccionamos Properties.

En la ventana que aparece pulsamos en Run y escribimos los parámetros en Arguments

Estos argumentos serán los que reciba main en el array args cuando ejecutemos el programa.

Java Ejercicios Básicos de Arrays Resueltos 2

Relación Nº 2: Ejercicios 3 y 4

3. Programa que lee por teclado la nota de los alumnos de una clase y calcula la nota media del grupo. También muestra los alumnos con notas superiores a la media. El número de alumnos se lee por teclado.
Este programa utiliza un array de elementos de tipo double que contendrá las notas de los alumnos. 
El tamaño del array será el número de alumnos de la clase, por lo tanto primero se pedirá por teclado el número de alumnos y a continuación se creará el array.
Se realizan 3 recorridos sobre el array, el primero para asignar a cada elemento las notas introducidas por teclado, el segundo para sumarlas y calcular la media y el tercero para mostrar los alumnos con notas superiores a la media.
import java.util.Scanner;
public class MediaDeLaClase {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int numAlum, i;
        double suma = 0, media;

        //Lectura del número de alumnos. Debe ser un valor positivo
        do {
            System.out.print("Número de alumnos de la clase: ");
            numAlum = sc.nextInt();
        } while (numAlum <= 0);

        //se crea un array llamado notas de numAlumn elementos de tipo double                                      
        double[] notas = new double[numAlum]; 
        
        // Entrada de datos. Se lee la nota de cada alummo y se guarda
        // en cada elemento del array
        for (i = 0; i < notas.length; i++) {
            System.out.print("Alumno " + (i + 1) + " Nota final: ");
            notas[i] = sc.nextDouble();
        }

        // Sumar todas las notas
        for (i = 0; i < notas.length; i++) {
            suma = suma + notas[i];
        }

        // Calcular la media
        media = suma / notas.length;

        // Mostrar la media
        System.out.printf("Nota media del curso: %.2f %n", media);

        // Mostrar los valores superiores a la media
        System.out.println("Listado de notas superiores a la media: ");
        for (i = 0; i < notas.length; i++) {
            if (notas[i] > media) {
                System.out.println("Alumno numero " + (i + 1)+ " Nota final: " + notas[i]);
            }
        }
    }
}


4. Programa que crea un array de 20 elementos llamado Pares y guarde los 20 primeros números pares. Mostrar por pantalla el contenido del array creado. 

/*
 * Programa que crea un array de 20 elementos llamado Pares y guarde los 20 primeros
 * números pares. Mostrar por pantalla el contenido del array creado
 */
import java.util.Scanner;
public class ArrayPares {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int i, cont = 2;

        int[] pares = new int[20];

        //Llenamos el array con números pares. Utilizamos un contador
        //con valor inicial 2 y le sumamos dos en cada iteración.
        for (i = 0; i < pares.length; i++) {
            pares[i] = cont;
            cont += 2;
        }
         
        //Mostrar el array
        for (i = 0; i < pares.length; i++) {
            System.out.println(pares[i]);
        }
    }
}

Java printf para dar formato a los datos de salida

Vamos a ver como utilizar printf para dar formato a los datos que se imprimen por pantalla en Java.
Este problema se nos plantea por ejemplo cuando queremos mostrar un número de tipo float o double con un número determinado de decimales y no con los que por defecto muestra Java.

A partir de la versión Java 5 se incorporan los métodos format y printf que permiten aplicar un formato a la salida de datos por pantalla.
Ambos realizan la misma función, tienen exactamente el mismo formato y emulan la impresión con formato printf() de C.


Veamos primero varios ejemplos de printf en Java y después explicaremos en detalle la sintaxis de printf.

Si queremos mostrar el número 12.3698 de tipo double con dos decimales:

System.out.printf("%.2f %n", 12.3698);

El primer % indica que en esa posición se va a escribir un valor. El valor a escribir se encuentra a continuación de las comillas.
.2 indica el número de decimales.
La f indica que el número es de tipo float o double. En la tabla que aparece más adelante podeis ver todos los carateres de conversión para todos los tipos de datos.
%n indica un salto de línea. Equivale a \n. Con printf podemos usar ambos para hacer un salto de línea.

La salida por pantalla es:
12,37

Comprobamos que printf realiza un redondeo para mostrar los decimales indicados.
Lo más común será que tengamos el valor en una variable, en ese caso si queremos escribir el valor de n con tres decimales:

double n = 1.25036;
System.out.printf("%.3f %n", n);
Salida:
1,250

Para mostrar el signo + en un número positivo:
double n = 1.25036;
System.out.printf("%+.3f %n", n);
Salida:
+1.250

Si el número a mostrar es un entero se utiliza el caracter d:
int x = 10;
System.out.printf("%d %n", x);
Salida:
10

Para mostrarlo con signo:
int x = 10;
System.out.printf("%+d %n", x);
Salida:
+10

Para mostrar varias variables pondremos tantos % como valores vamos a mostrar. Las variables se escriben a continuación de las comillas separadas por comas:

double n = 1.25036;
int x = 10;
System.out.printf("n = %.2f x = %d %n", n, x);
Salida:
n = 1,25 x = 10

Cuando hay varias variables podemos indicar de cual de ellas es el valor a mostrar escribiendo 1$, 2$, 3$, ... indicando que el valor a mostrar es el de la primera variable que aparece a continuación de las comillas, de la segunda, etc.
La instrucción anterior la podemos escribir así:
System.out.printf("n = %1$.2f x = %2$d %n", n, x);

Este número es opcional, si no aparece se entenderá que el primer valor proviene de la primera variable, el segundo de la segunda, etc.

Si queremos mostrar el número 123.4567 y su cuadrado ambos con dos decimales debemos escribir:
double n = 123.4567;
System.out.printf("El cuadrado de %.2f es %.2f\n", n, n*n);
Salida:
El cuadrado de 123,46 es 15241,56

printf permite mostrar valores con un ancho de campo determinado. Por ejemplo, si queremos mostrar el contenido de n en un ancho de campo de 10 caracteres escribimos:

double n = 1.25036;
System.out.printf("%+10.2f %n", n);
Salida:
bbbbb+1.25
Donde cada b indica un espacio en blanco.
El 10 indica el tamaño en caracteres que ocupará el número en pantalla. Se cuentan además de las cifras del número el punto decimal y el signo si lo lleva. En este caso el número ocupa un espacio de 5 caracteres (3 cifras, un punto y el signo) por lo tanto se añaden 5 espacios en blanco al principio para completar el tamaño de 10.

Si queremos que en lugar de espacios en blancos nos muestre el número completando el ancho con ceros escribimos:
System.out.printf("%+010.2f %n", n);
Salida:
+000001.25

Más ejemplos de printf:

Mostrar el número 1.22 en un ancho de campo de 10 caracteres y con dos decimales.

double precio = 1.22;
System.out.printf("%10.2f", precio);

Salida:
bbbbbb1.22 
(el carácter b indica un espacio en blanco)
El número ocupa un espacio total de 10 caracteres incluyendo el punto y los dos decimales.

Mostrar la cadena "Total:" con un ancho de 10 caracteres y alineada a la izquierda:

System.out.printf("%-10s", "Total:");

Salida:
Total:bbbb

El caracter s indica que se va a mostrar una cadena de caracteres.
El signo - indica alineación a la izquierda.

Mostrar la cadena "Total:" con un ancho de 10 caracteres y alineada a la derecha:

System.out.printf("%10s", "Total:");

Salida:
bbbbTotal:

Al final puedes ver un ejemplo completo con distintos usos de printf.


Veamos ahora detenidamente la sintaxis de printf:

La sintaxis general de printf es:
printf (String de formato, Object … datos);

El String de formato es una cadena de caracteres que contiene:
- texto fijo que será mostrado tal cual
- especificadores de formato que determinan la forma en que se van mostrar los datos.
datos representa la información que se va a mostrar y sobre la que se aplica el formato. El número de datos que se pueden mostrar es variable.




Explicación de cada una de las partes que aparecen en la instrucción printf:

Especificadores de formato:

La sintaxis para los especificadores de formato de printf es:
%[posición_dato$][indicador_de_formato][ancho][.precision]carácter_de_conversión

Los elementos entre corchetes son opcionales.

posición_dato: indica la posición del dato sobre el que se va aplicar el formato. El primero por la izquierda ocupa la posición 1.

indicador_de_formato: es el conjunto de caracteres que determina el formato de salida. Los indicadores de formato de printf en Java son:


ancho: Indica el tamaño mínimo, medido en número de caracteres, que debe ocupar el dato en pantalla.

.precision: Indica el número de decimales que serán representados. Solo aplicable a datos de tipo float o double.

carácter_de_conversión: Carácter que indica cómo tiene que ser formateado el dato. Los más utilizados se muestran en la tabla.


Ejemplo completo con distintos usos de printf en Java:

public static void main(String[] args) {
     double q = 1.0/3.0;
     System.out.printf ("1.0/3.0 = %5.3f %n", q);
     System.out.printf ("1.0/3.0 = %7.5f %n", q);
     q = 1.0/2.0;
     System.out.printf ("1.0/2.0 = %09.3f %n", q);
     q = 1000.0/3.0;
     System.out.printf ("1000/3.0 = %7.1e h%n", q);
     q = 3.0/4567.0;
     System.out.printf ("3.0/4567.0 = %7.3e %n", q);
     q = -1.0/0.0;
     System.out.printf ("-1.0/0.0 = %7.2e %n", q);
     q = 0.0/0.0;
     System.out.printf ("0.0/0.0 = %5.2e %n", q);
     System.out.printf ("pi = %5.3f, e = %10.4f %n", Math.PI, Math.E);
     double r = 1.1;
     System.out.printf

            ("C = 2 * %1$5.5f * %2$4.1f, "+"A = %2$4.1f * %2$4.1f * %1$5.5f %n",Math.PI, r);
}



 Salida:

1.0/3.0 = 0,333
1.0/3.0 = 0,33333
1.0/2.0 = 00000,500
1000/3.0 = 3,3e+02 h
3.0/4567.0 = 6,569e-04
-1.0/0.0 = -Infinity
0.0/0.0 = NaN
pi = 3,142, e = 2,7183
C = 2 * 3,14159 * 1,1, A = 1,1 * 1,1 * 3,14159

Puedes encontrar más ejercicios para seguir practicando en este libro.


Contiene ejercicios resueltos sobre los conceptos básicos del lenguaje java: Declaración de variables, literales, tipos de datos, operadores, crear expresiones algebraicas correctas, etc.

Las soluciones de los ejercicios incluyen una explicación detallada sobre cómo se ha resuelto.

El contenido del libro es una recopilación de ejercicios realizados en mis clases de Programación en los ciclos formativos de grado superior Desarrollo de aplicaciones web y Desarrollo de aplicaciones multiplataforma.

Java Scanner para lectura de datos

La clase Scanner se utiliza para la lectura de datos en los programas Java.
Primero veremos varios ejemplos de lectura de datos en Java con Scanner y después explicaremos en detalle como funciona.
Para utilizar Scanner en el programa tendremos que hacer lo siguiente:
1. Escribir el import
La clase Scanner se encuentra en el paquete java.util por lo tanto se debe incluir al inicio del programa la instrucción:
import java.util.Scanner;
2. Crear un objeto Scanner
Tenemos que crear un objeto de la clase Scanner asociado al dispositivo de entrada.
Si el dispositivo de entrada es el teclado escribiremos:
Scanner sc = new Scanner(System.in);
Se ha creado el objeto sc asociado al teclado representado por System.in
Una vez hecho esto podemos leer datos por teclado. 
3. Utilizar el Scanner
Para leer datos desde teclado con Scanner podemos usar los métodos nextXxx() donde Xxx indica el tipo de dato a leer:
  • nextByte()  para leer un dato de tipo byte.
  • nextShort()  para leer un dato de tipo short.
  • nextInt()  para leer un dato de tipo int.
  • nextLong()  para leer un dato de tipo long. 
  • nextFloat()  para leer un dato de tipo float. 
  • nextDouble()  para leer un dato de tipo double. 
  • nextBoolean()  para leer un dato de tipo boolean.
  • nextLine()  para leer un String hasta encontrar un salto de línea.
  • next()  para leer un String hasta el primer delimitador, generalmente hasta un espacio en blanco o hasta un salto de línea.  
 
Ejemplos de lectura:
Ejemplo de lectura por teclado de un número entero (tipo int):
int n;
System.out.print("Introduzca un número entero: ");
n = sc.nextInt(); //asigna a la variable n el número entero introducido por teclado    
Ejemplo de lectura de un número de tipo double:
double x;
System.out.print("Introduzca número de tipo double: ");
x = sc.nextDouble(); //asigna a la variable x el número double introducido por teclado 
Ejemplo de lectura de una cadena de caracteres (String):
String s;
System.out.print("Introduzca texto: ");
s = sc.nextLine(); //asigna a la variable s el String introducido por teclado          
Ejemplo de lectura de un número de tipo long:
long ln;
System.out.print("Introduzca un número: ");
ln = sc.nextLong(); //asigna a la variable ln el número long introducido por teclado   
Si el valor introducido por teclado no es del tipo esperado o de un tipo compatible al esperado, se produce un error. En este caso se lanza la excepción InputMismatchException
Ejemplo completo de programa Java con lectura de datos con Scanner:
El programa pide al usuario que introduzca por teclado su nombre y lo muestra por pantalla. A continuación pide que se introduzca por rteclado el valor del radio de una circunferencia de tipo double y muestra la longitud de la circunferencia. Además pide que se introduzca por teclado un número entero y muestra su cuadrado.
import java.util.Scanner;  //import de la clase Scanner

public class Ejemplo1Scanner {

    public static void main(String[] args) {  

           Scanner sc = new Scanner(System.in);  //Se crea un objeto Scanner
           String nombre;
           double radio;
           int n;

           System.out.print("Introduzca su nombre: ");       
           nombre = sc.nextLine();  //leer un String
           System.out.println("Hola " + nombre + "!!!");

           System.out.print("Introduzca el radio de la circunferencia: ");
           radio = sc.nextDouble(); //leer un double
           System.out.println("Longitud de la circunferencia: " + 2*Math.PI*radio);                
           
           System.out.print("Introduzca un número entero: ");
           n = sc.nextInt(); //leer un entero
           System.out.println("El cuadrado es: " + Math.pow(n,2));
     }
}
Funcionamiento interno de la clase Java Scanner.
Es importante conocer el funcionamiento interno de la clase Scanner para poder realizar las operaciones de lectura de forma correcta.
De forma resumida, el proceso de lectura por teclado en un programa Java es el siguiente:
  • Los datos que se introducen desde teclado se almacenan en una zona de memoria que vamoso a llamar buffer
  • Mediante un stream estos datos pasan al programa.
Un stream o flujo de datos es un objeto que hace de intermediario entre el programa y el origen o el destino de los datos. El programa lee del stream o escribe en él, sin importarle de donde proceden los datos físicamente o hacia qué dispositivo se dirigen realmente.
Un stream está formado por una secuencia de bytes utilizados para la entrada o salida de un programa.
Java crea de forma automática los siguientes streams cuando se ejecuta un programa: 
System.in: stream de entrada conectado al teclado 
System.out: stream de salida conectado al monitor
System.err: stream de salida conectado al monitor para mensajes de error.
Además de estos streams estándar, java proporciona una gran cantidad de clases para streams que permiten leer y escribir en ficheros.
  • Cuando en el programa aparece una instrucción para leer un dato por teclado, se accede al buffer de entrada en busca del dato. Si lo encuentra, lo extrae del buffer y lo incorpora al programa.
  • Si el dato no ha sido encontrado en el buffer generalmente se deberá a que el buffer está vacío. Esta es la situación más habitual. En este caso el programa espera a que el usuario introduzca el dato por teclado. Cuando el usuario lo introduce y pulsa intro entonces se extrae el valor introducido del buffer y se incorpora al programa.
  • Si el dato encontrado no es del tipo esperado o de un tipo compatible se produce un error. En este caso se lanza la excepción InputMismatchException. Esto se produce, por ejemplo, cuando se está ejecutando el método nextInt() para extraer un entero del buffer y se introduce por ejemplo un double o un char. El tipo de dato encontrado en el buffer no coincide con el tipo que se quiere leer.
Ejemplo: acciones internas que se realizan cuando se lee un número entero desde teclado.
int n;
System.out.print("Introduzca un número entero: ");     
n = sc.nextInt();  
Mediante la instrucción sc.nextInt() Scanner accede al buffer de entrada para obtener un dato de tipo int y asignarlo a la variable n.
Si en el buffer no hay nada (que será lo más habitual) el programa espera a que se introduzca un número. Cuando el usuario introduce el número y pulsa intro, se extrae ese número del buffer y se lo asigna a la variable n.


Importante: cuando se introducen datos desde teclado, se pueden introducir varios valores separados por espacios en blanco.
Por ejemplo, para el ejemplo anterior se podría haber introducido:
12 2.1 5
A continuación, utilizando los métodos adecuados de la clase Scanner se puede acceder a esos tokens y trabajar con ellos en el programa.
 
Ejemplo: acciones internas que se realizan cuando se quiere leer un número entero desde teclado pero se han introducido varios valores separados por espacios en blanco.
int n;
System.out.print("Introduzca un número entero: ");               
n = sc.nextInt(); 

Debemos tener claro el funcionamiento de Scanner en estos casoso para evitar errores durante la ejecución del programa.
 
Si apartir de esta situación del buffer se pide al usuario que introduzca otro número entero:
System.out.print("Introduzca otro número entero: ");      
n = sc.nextInt();          
Ahora de forma interna se realizarían las siguientes acciones:
 

Para evitar estos errores la clase Scanner proporciona métodos para saber si hay tokens en el buffer y para saber el tipo del siguiente token a extraer: 
 
  • hasNext():  Devuelve un boolean. Indica si existe o no un siguiente token para extraer.
  • hasNextXxx():  Devuelve un boolean. Indica si el siguiente token a extraer es del tipo especificado por Xxx, por ejemplo hasNextInt(), hasNextDouble(), etc.
Ejemplo: programa que lee por teclado un número entero positivo. Si el valor introducido no es un número entero positivo se muestra un mensaje y se vuelve a pedir.
import java.util.Scanner;
public class Ejemplo2Scanner {
       public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              int N;
              do {
                  System.out.print("Introduce un número entero positivo: ");
                  while (!sc.hasNextInt()) {
                         System.out.println("Valor no válido");
                         sc.next();
                         System.out.print("Introduce un número entero positivo: ");                               
                  }
                  N = sc.nextInt();
                  if(N <= 0){
                     System.out.println("El número debe ser positivo");                                           
                  }
              } while (N <= 0);
              System.out.println("Número introducido: " + N);
       }
}
En el programa se ha utilizado el método hasNextInt() para comprobar si el número que se introduce por teclado es de tipo int. El método hasNextInt() accede al buffer para comprobar si el siguiente token a extraer es un int. Si encuentra el buffer vacío espera a que el usuario introduzca un valor y una vez introducido comprueba su tipo. Si no es un int devuelve false. El while se está ejecutando mientras que el dato introducido por teclado no sea de tipo int.

Dentro del while aparece la instrucción:

sc.next();

Esta instrucción sirve para extraer del buffer el número no válido introducido. Es necesario escribirla ahí porque si no lo hacemos provocaremos que ese while se convierta en un bucle infinito. El dato no válido introducido seguirá estando en el buffer con lo que el método hasNextInt() comprobará de nuevo que no es válido y así seguirá indefinidamente.

  
Otro método que puede resultarnos útil cuando trabajamos con Scanner es el método  useDelimiter(String) que sirve para establecer un nuevo delimitador de tokens.

Cómo limpiar el buffer de entrada en Java
En el ejemplo anterior hemos visto que en ocasiones es necesario extraer del buffer de entrada los datos no válidos introducidos.
 
En el ejemplo se ha eliminado el dato con el método next().
 
Podemos limpiar el buffer mediante dos métodos:
  • next() extrae del buffer el siguiente token en forma de String. Debemos tener en cuenta que este método solo extrae un token, si hubiese más permanecerían en el buffer.
  • nextLine() extrae del buffer un String con todo el contenido del buffer hasta encontrar un salto de línea. El salto de línea no se incluye en el String devuelto. El salto de línea se elimina del buffer.
Cuando se introducen datos de distinto tipo desde teclado habrá situaciones en la que será necesario eliminar totalmente el contenido del buffer de entrada. De otro modo la lectura de datos no se realizará de forma correcta, en particular cuando se intenten introducir datos de tipo String.
 
Ejemplo: Programa que lee por teclado el nombre, edad y dirección de una persona y lo muestra por pantalla.
import java.util.Scanner;
public class Ejemplo3Scanner {
       public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              String nombre, direccion;
              int edad;
              System.out.print("Introduce tu nombre: ");
              nombre = sc.nextLine(); //leer el nombre
              System.out.print("Introduce tu edad: ");
              edad = sc.nextInt(); //leer la edad
              System.out.print("Introduce tu dirección: ");
              direccion = sc.nextLine(); //leer la dirección                                                      
              System.out.println("Datos introducidos");
              System.out.println("Nombre: " + nombre);
              System.out.println("Edad: " + edad);
              System.out.println("Dirección: " + direccion);                                                      
       }
}
Si lo ejecutamos vemos que la lectura de datos no se realiza de forma correcta:
Introduce tu nombre: Juan Redondo
Introduce tu edad: 25
Introduce tu dirección: Datos introducidos                                                                        
Nombre: Juan Redondo
Edad: 25
Dirección:
Se ha leído por teclado el nombre y la edad pero el programa no se ha detenido para que el usuario introduzca la dirección por lo que la variable dirección queda sin valor.
 
La explicación a lo que ha ocurrido podemos verla de forma gráfica:
Primero se introduce el nombre por teclado:

La siguiente operación de lectura por teclado es la edad:

La siguiente operación de lectura por teclado es la dirección:


Después de leer la edad, el intro permanece en el buffer y si después intentamos leer un String, la lectura por teclado no se realizará.
 
La solución es sencilla:
 
Limpiar el buffer después de leer el número entero mediante el método nextLine();
 
El programa quedaría así:
import java.util.Scanner;
public class Ejemplo3Scanner {
       public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              String nombre, direccion;
              int edad;
              System.out.print("Introduce tu nombre: ");
              nombre = sc.nextLine(); //leer el nombre
              System.out.print("Introduce tu edad: ");
              edad = sc.nextInt(); //leer la edad
			  
              sc.nextLine(); //limpiar el buffer de entrada
			  
              System.out.print("Introduce tu dirección: ");
              direccion = sc.nextLine(); //leer la dirección                                                      
              System.out.println("Datos introducidos");
              System.out.println("Nombre: " + nombre);
              System.out.println("Edad: " + edad);
              System.out.println("Dirección: " + direccion);                                                      
       }
}
Ahora, después de introducir la edad, el método nextLine() elimina el intro que ha quedado en el buffer por lo que la lectura de la dirección se realizará de forma correcta.
Introduce tu nombre: Juan Redondo
Introduce tu edad: 25
Introduce tu dirección: C/Mayor 134 - Madrid.                                                                     
Datos introducidos
Nombre: Juan Redondo                                                                                              
Edad: 25
Dirección: C/Mayor 134 - Madrid.
En general se debe limpiar el buffer de entrada de Scanner cuando tengamos que introducir un dato de tipo String después de haber introducido un dato de tipo numérico

Si quieres ver más ejemplos de entrada de datos en Java con Scanner los tienes en este enlace Ejercicios con Scanner en Java


Puedes encontrar más ejercicios para seguir practicando en este libro.


Contiene ejercicios resueltos sobre los conceptos básicos del lenguaje java: Declaración de variables, literales, tipos de datos, operadores, crear expresiones algebraicas correctas, etc.

Las soluciones de los ejercicios incluyen una explicación detallada sobre cómo se ha resuelto.

El contenido del libro es una recopilación de ejercicios realizados en mis clases de Programación en los ciclos formativos de grado superior Desarrollo de aplicaciones web y Desarrollo de aplicaciones multiplataforma.