Articolo originale: https://www.freecodecamp.org/news/java-scanner-nextline-call-gets-skipped-solved/

C'è un errore che spesso disorienta i nuovi programmatori Java. Si verifica quando una serie di prompt di input vengono raggruppati insieme e una delle chiamate del metodo scanner.nextLine() viene saltata – senza alcuna traccia di errore.

Dai un'occhiata al seguente snippet, ad esempio:

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Come ti chiami? ");
        String name = scanner.nextLine();

        System.out.printf("Ciao %s. Quanti anni hai? ", name);
        int age = scanner.nextInt();

        System.out.printf("Bene! %d anni sono un'ottima età per imparare a programmare. \nChe linguaggio preferisci? ", age);
        String language = scanner.nextLine();

        System.out.printf("Ah! %s è un linguaggio di programmazione molto valido.", language);

        scanner.close();

    }

}

La prima chiamata scanner.nextLine() chiede all'utente il suo nome. Poi la chiamata scanner.nextInt() chiede all'utente la sua età. L'ultima chiamata scanner.nextLine() chiede all'utente il suo linguaggio di programmazione preferito. Infine chiudi l'oggetto scanner e la finisci qui.

Si tratta di codice Java molto semplice, che fa uso di un oggetto scanner per prendere un input dall'utente. Proviamo a eseguire il programma e vediamo cosa accade.

Se hai eseguito il programma, probabilmente hai notato che chiede il nome, l'età e poi salta l'ultima richiesta di input per il linguaggio di programmazione preferito, terminando di colpo. Ecco quello che andremo a risolvere oggi.

Perché la chiamata scanner.nextLine() viene saltata dopo la chiamata scanner.nextInt()?

Questo comportamento non è limitato solo al metodo scanner.nextInt(). Se chiami il metodo scanner.nextLine() dopo uno qualsiasi dei metodi scanner.nextQualcosa(), il programma salterà quella chiamata.

Ciò ha a che fare con il modo in cui funzionano i due metodi. Il primo scanner.nextLine() richiede all'utente il suo nome.

Quando l'utente digita il suo nome e preme invio, scanner.nextLine() utilizza il nome e l'invio o il carattere nuova riga alla fine.

Questo vuol dire che il buffer degli input è attualmente vuoto. Quindi il metodo scanner.nextInt() chiede all'utente la sua età. L'utente la digita e preme invio.

A differenza del metodo scanner.nextLine(), il metodo scanner.nextInt() utilizza soltanto la parte intera e lascia l'invio o il carattere nuova riga nel buffer.

Quando viene chiamato lo scanner.nextLine() successivo, trova il carattere nuova riga ancora presente nel buffer degli input e lo interpreta erroneamente come l'input dell'utente.

Come puoi vedere, come molti altri problemi della vita reale, tutto ciò è causato da un'incomprensione tra l'utente e il programmatore.

Esistono due modi per risolvere il problema. Puoi utilizzare il carattere nuova riga dopo che avviene la chiamata di scanner.nextInt() oppure puoi prendere tutti gli input come stringhe per poi convertirli successivamente nei tipi di dato corretti.

Come svuotare il buffer degli input dopo la chiamata scanner.nextInt()

È più facile di quanto pensi. Tutto ciò che devi fare è aggiungere un'altra chiamata scanner.nextLine() dopo la chiamata scanner.nextInt().

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Come ti chiami? ");
        String name = scanner.nextLine();

        System.out.printf("Ciao %s. Quanti anni hai? ", name);
        int age = scanner.nextInt();

        // utilizza il carattere nuova riga nel buffer
        scanner.nextLine();

        System.out.printf("Bene! %d anni sono un'ottima età per imparare a programmare. \nChe linguaggio preferisci? ", age);
        String language = scanner.nextLine();

        System.out.printf("Ah! %s è un linguaggio di programmazione molto valido.", language);

        scanner.close();

    }

}

Sebbene questa soluzione funzioni, occorre aggiungere una chiamata aggiuntiva scanner.nextLine() ogni volta che chiami uno degli altri metodi. Va bene per piccoli programmi, ma per programmi più complessi può degenerare molto in fretta.

Come interpretare gli input presi usando il metodo scanner.nextLine()

Tutta la classe wrapper in Java contiene metodi per interpretare valori stringa. Ad esempio, il metodo Integer.parseInt() può interpretare un valore intero da una data stringa.

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Come ti chiami? ");
        String name = scanner.nextLine();

        System.out.printf("Ciao %s. Quanti anni hai? ", name);
        // interpreta l'intero dalla stringa
        int age = Integer.parseInt(scanner.nextLine());

        System.out.printf("Bene! %d anni sono un'ottima età per imparare a programmare. \nChe linguaggio preferisci? ", age);
        String language = scanner.nextLine();

        System.out.printf("Ah! %s è un linguaggio di programmazione molto valido.", language);

        scanner.close();

    }

}

Questo è un modo più pulito per combinare richieste di più tipi di input in Java. Finché fai attenzione a quello che l'utente sta inserendo, il parsing non dovrebbe dare problemi.

Conclusione

Grazie di cuore per interessarti a quello che scrivo. Spero che questo tutorial ti abbia aiutato in qualche modo.

Se lo hai trovato utile, condividilo con i tuoi amici. E se vuoi seguirmi, sono su Twitter e LinkedIn.