Lo scanner sta saltando nextLine () dopo aver usato next () o nextFoo ()?

Sto usando i metodi Scanner nextInt() e nextLine() per l’input di lettura.

Sembra questo:

 System.out.println("Enter numerical value"); int option; option = input.nextInt(); // Read numerical value from input System.out.println("Enter 1st string"); String string1 = input.nextLine(); // Read 1st string (this is skipped) System.out.println("Enter 2nd string"); String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value) 

Il problema è che dopo aver inserito il valore numerico, il primo input.nextLine() viene saltato e viene eseguito il secondo input.nextLine() , in modo che il mio output assomigli a questo:

 Enter numerical value 3 // This is my input Enter 1st string // The program is supposed to stop here and wait for my input, but is skipped Enter 2nd string // ...and this line is executed and waits for my input 

Ho provato la mia applicazione e sembra che il problema risieda nell’uso di input.nextInt() . Se lo elimino, allora sia string1 = input.nextLine() che string2 = input.nextLine() vengono eseguiti come voglio che siano.

Questo perché il metodo Scanner.nextInt non consuma l’ ultimo carattere di nuova riga del tuo input, e quindi quella nuova riga viene consumata nella prossima chiamata a Scanner.nextLine .

Si verificherà un comportamento simile quando si utilizza Scanner.nextLine dopo Scanner.next() o qualsiasi metodo Scanner.nextFoo (ad eccezione di nextLine stesso).

Soluzione:

  • Esegui una chiamata Scanner.nextLine vuota dopo Scanner.nextInt o Scanner.nextFoo per consumare il resto di tale linea, incluso newline

     int option = input.nextInt(); input.nextLine(); // Consume newline left-over String str1 = input.nextLine(); 
  • Oppure, sarebbe ancora meglio se leggi l’input tramite Scanner.nextLine e converti l’input nel formato corretto di cui hai bisogno. Ad esempio, a un intero che utilizza il metodo Integer.parseInt(String) .

     int option = 0; try { option = Integer.parseInt(input.nextLine()); } catch (NumberFormatException e) { e.printStackTrace(); } String str1 = input.nextLine(); 

Il problema è con il metodo input.nextInt () – legge solo il valore int. Quindi quando continui a leggere con input.nextLine () ricevi il tasto “\ n” Invio. Quindi per saltare questo devi aggiungere l’ input.nextLine () . Spero che questo dovrebbe essere chiaro ora.

Provalo così:

 System.out.print("Insert a number: "); int number = input.nextInt(); input.nextLine(); // This line you have to add (It consumes the \n character) System.out.print("Text1: "); String text1 = input.nextLine(); System.out.print("Text2: "); String text2 = input.nextLine(); 

È perché quando inserisci un numero, premi Invio , input.nextInt() consuma solo il numero, non il “fine della riga”. Quando input.nextLine() eseguito input.nextLine() , esso consuma la “fine della riga” ancora nel buffer dal primo input.

Utilizzare invece input.nextLine() immediatamente dopo input.nextInt()

Sembra che ci siano molte domande su questo problema con java.util.Scanner . Penso che una soluzione più leggibile / idiomatica sarebbe chiamare scanner.skip("[\r\n]+") per eliminare qualsiasi carattere di nuova riga dopo aver chiamato nextInt() .

EDIT: come indicato da @PatrickParker di seguito, ciò causerà un loop infinito se l’utente immette qualsiasi spazio bianco dopo il numero. Vedi la loro risposta per un modello migliore da usare con skip: https://stackoverflow.com/a/42471816/143585

Lo fa perché input.nextInt(); non cattura la nuova riga. potresti fare come gli altri proposti aggiungendo un input.nextLine(); sotto.
In alternativa puoi farlo in stile C # e analizzare un nextLine in un intero in questo modo:

 int number = Integer.parseInt(input.nextLine()); 

Fare questo funziona altrettanto bene e ti fa risparmiare una riga di codice.

Cose che devi sapere:

  • il testo che rappresenta poche righe contiene anche caratteri non stampabili tra linee (noi li chiamiamo separatori di linee) come

    • carriage return (CR – in String letterals rappresentato come "\r" )
    • avanzamento riga (LF – in String letterals rappresentato come "\n" )
  • quando stai leggendo i dati dalla console, consente all’utente di digitare la sua risposta e quando ha finito ha bisogno di confermare in qualche modo quel fatto. Per fare ciò, l’utente deve premere il tasto “invio” / “ritorno” sulla tastiera.

    Ciò che è importante è che questo tasto oltre a garantire l’immissione dei dati utente sullo standard input (rappresentato da System.in che viene letto da Scanner ) invia anche i separatori di riga dipendenti dal SO (come per Windows \r\n ) dopo di esso.

    Pertanto, quando si chiede all’utente valori come age e tipi di utente 42 e si preme Invio, l’input standard conterrà "42\r\n" .

Problema

Scanner#nextInt (e altri metodi del Scanner#next Type Scanner#nextInt Scanner#next Type ) non consente a Scanner di consumare questi separatori di riga. Li leggerà da System.in (in quale altro modo Scanner potrebbe sapere che non ci sono più cifre da parte dell’utente che rappresentano il valore age rispetto agli spazi bianchi?) Che li rimuoverà dall’input standard, ma memorizzerà internamente anche i separatori di riga . Quello che dobbiamo ricordare, è che tutti i metodi dello scanner sono sempre in scansione a partire dal testo memorizzato nella cache.

Now Scanner#nextLine() semplicemente raccoglie e restituisce tutti i caratteri fino a quando non trova i separatori di riga (o la fine del stream). Ma poiché i separatori di riga dopo aver letto il numero dalla console si trovano immediatamente nella cache dello Scanner, restituiscono String vuota, ovvero Scanner non è stato in grado di trovare alcun carattere prima di questi separatori di riga (o fine del stream).
BTW nextLine consuma anche quei separatori di linea.

Soluzione

Quindi quando vuoi chiedere il numero e poi per l’intera riga evitando quella stringa vuota come risultato di nextLine , neanche

  • consumare il separatore di riga lasciato da nextInt dalla cache degli scanner di
    • chiamare nextLine ,
    • oppure chiamando skip("\\R") per lasciare che Scanner salvi la parte abbinata a \R che rappresenta il separatore di riga (maggiori informazioni su \R : https://stackoverflow.com/a/31060125 )
  • non utilizzare affatto i metodi nextInt (né next o nextTYPE ). Piuttosto, leggi interi dati riga per riga usando nextLine e analizza i numeri da ogni riga (assumendo che una riga contenga un solo numero) al tipo corretto come int tramite Integer.parseInt .

BTW : Scanner#next Type metodi Scanner#next Type possono saltare i delimitatori (per impostazione predefinita tutti gli spazi bianchi come tabs, separatori di riga) inclusi quelli memorizzati nello scanner, fino a quando non troveranno il successivo valore non delimitatore (token). Grazie a quello per l’input come il codice "42\r\n\r\n321\r\n\r\n\r\nfoobar"

 int num1 = sc.nextInt(); int num2 = sc.nextInt(); String name = sc.next(); 

sarà in grado di assegnare correttamente num1=42 num2=321 name=foobar .

Invece di input.nextLine() usa input.next() , questo dovrebbe risolvere il problema.

Codice modificato:

 public static Scanner input = new Scanner(System.in); public static void main(String[] args) { System.out.print("Insert a number: "); int number = input.nextInt(); System.out.print("Text1: "); String text1 = input.next(); System.out.print("Text2: "); String text2 = input.next(); } 

Per evitare il problema, usa nextLine(); immediatamente dopo nextInt(); come aiuta a chiarire il buffer. Quando si preme ENTER il nextInt(); non acquisisce la nuova riga e quindi salta il codice dello Scanner secondo momento.

 Scanner scanner = new Scanner(System.in); int option = scanner.nextInt(); scanner.nextLine(); //clearing the buffer 

Se si desidera eseguire la scansione veloce dell’input senza confondersi con il metodo nextLine () della class Scanner, utilizzare Custom Input Scanner per questo.

Codice :

 class ScanReader { /** * @author Nikunj Khokhar */ private byte[] buf = new byte[4 * 1024]; private int index; private BufferedInputStream in; private int total; public ScanReader(InputStream inputStream) { in = new BufferedInputStream(inputStream); } private int scan() throws IOException { if (index >= total) { index = 0; total = in.read(buf); if (total <= 0) return -1; } return buf[index++]; } public char scanChar(){ int c=scan(); while (isWhiteSpace(c))c=scan(); return (char)c; } public int scanInt() throws IOException { int integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == '-') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= '0' && n <= '9') { integer *= 10; integer += n - '0'; n = scan(); } } return neg * integer; } public String scanString() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); StringBuilder res = new StringBuilder(); do { res.appendCodePoint(c); c = scan(); } while (!isWhiteSpace(c)); return res.toString(); } private boolean isWhiteSpace(int n) { if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true; else return false; } public long scanLong() throws IOException { long integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == '-') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= '0' && n <= '9') { integer *= 10; integer += n - '0'; n = scan(); } } return neg * integer; } public void scanLong(long[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanLong(); } public void scanInt(int[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanInt(); } public double scanDouble() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); int sgn = 1; if (c == '-') { sgn = -1; c = scan(); } double res = 0; while (!isWhiteSpace(c) && c != '.') { if (c == 'e' || c == 'E') { return res * Math.pow(10, scanInt()); } res *= 10; res += c - '0'; c = scan(); } if (c == '.') { c = scan(); double m = 1; while (!isWhiteSpace(c)) { if (c == 'e' || c == 'E') { return res * Math.pow(10, scanInt()); } m /= 10; res += (c - '0') * m; c = scan(); } } return res * sgn; } } 

Vantaggi:

  • Scansioni Input più veloce di BufferReader
  • Riduce la complessità del tempo
  • Flushes Buffer per ogni input successivo

Metodi:

  • scanChar () - scansiona un singolo carattere
  • scanInt () - scan valore intero
  • scanLong () - scansiona il valore lungo
  • scanString () - scansiona il valore di stringa
  • scanDouble () - scan Double value
  • scanInt (int [] array) - esegue la scansione completa di Array (Integer)
  • scanLong (long [] array) - scansioni complete Array (Long)

Uso:

  1. Copia il codice indicato sotto il tuo codice java.
  2. Inizializza l'object per una determinata class

ScanReader sc = new ScanReader(System.in); 3. Importare le classi necessarie:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Lanciare IOException dal metodo principale per gestire Eccezione 5. Utilizzare i metodi forniti. 6. Divertiti

Esempio :

 import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; class Main{ public static void main(String... as) throws IOException{ ScanReader sc = new ScanReader(System.in); int a=sc.scanInt(); System.out.println(a); } } class ScanReader.... 

Se si desidera leggere stringhe e stringhe, una soluzione consiste nell’utilizzare due scanner:

 Scanner stringScanner = new Scanner(System.in); Scanner intScanner = new Scanner(System.in); intScanner.nextInt(); String s = stringScanner.nextLine(); // unaffected by previous nextInt() System.out.println(s); intScanner.close(); stringScanner.close(); 

sc.nextLine() è migliore rispetto sc.nextLine() dell’input. Perché le prestazioni saggi saranno buone.

 public static void main(String[] args) { Scanner scan = new Scanner(System.in); int i = scan.nextInt(); scan.nextLine(); double d = scan.nextDouble(); scan.nextLine(); String s = scan.nextLine(); System.out.println("String: " + s); System.out.println("Double: " + d); System.out.println("Int: " + i); } 

Il mio test ha prodotto gli stessi risultati di Prine, tuttavia ho pensato a una soluzione abbastanza semplice:

Usando BufferedReader#nextLine() , dove si dovrebbe Scanner#readLine() , evita questo bug. Si potrebbe anche scrivere il proprio wrapper Scanner per sovrascrivere la funzione readLine dello scanner con la funzione nextLine di BufferedReader.

Immagino di essere in ritardo per la festa ..

Come precedentemente affermato, la chiamata a input.nextLine() dopo aver ottenuto il valore int risolverà il problema. Il motivo per cui il tuo codice non ha funzionato era perché non c’era nient’altro da memorizzare dal tuo input (dove hai immesso l’int) in string1 . Farò solo un po ‘più di luce sull’intero argomento.

Considera nextLine () come il dispari tra i metodi nextFoo () nella class Scanner. Facciamo un esempio veloce. Diciamo che abbiamo due righe di codice come quelle qui sotto:

 int firstNumber = input.nextInt(); int secondNumber = input.nextInt(); 

Se inseriamo il valore sotto (come una singola riga di input)

54 234

Il valore della variabile firstNumber e secondNumber diventa rispettivamente 54 e 234. Il motivo per cui questo funziona in questo modo è perché un nuovo feed di riga ( cioè \ n ) NON viene generato automaticamente quando il metodo nextInt () accetta i valori. Prende semplicemente il “prossimo int” e procede. Questo è lo stesso per il resto dei metodi nextFoo () tranne nextLine ().

nextLine () genera un nuovo feed di riga immediatamente dopo aver preso un valore; questo è ciò che @RohitJain intende dicendo che il nuovo feed di riga è “consumato”.

Infine, il metodo next () prende semplicemente la Stringa più vicina senza generare una nuova linea; questo rende questo il metodo preferenziale per prendere Stringhe separate all’interno della stessa linea singola.

Spero che questo aiuti .. Buon codice!

Perché non utilizzare un nuovo scanner per ogni lettura? Come sotto Con questo approccio non affronterai il tuo problema.

 int i = new Scanner(System.in).nextInt();