Сканер пропускает nextLine() после использования next() или nextFoo()?

Я использую Scanner методы nextInt() а также nextLine() для чтения ввода.

Это выглядит так:

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)

Проблема в том, что после ввода числового значения первое input.nextLine() пропускается и второй input.nextLine() выполняется, так что мой вывод выглядит так:

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

Я протестировал свое приложение, и похоже, что проблема заключается в использовании input.nextInt(), Если я удалю его, то оба string1 = input.nextLine() а также string2 = input.nextLine() выполнены так, как я хочу, чтобы они были.

26 ответов

Решение

Это потому что Scanner.nextInt Метод не читает символ новой строки в вашем вводе, созданный нажатием "Enter", и поэтому вызов Scanner.nextLine возвращается после прочтения этой новой строки.

Вы столкнетесь с похожим поведением при использовании Scanner.nextLine после Scanner.next() или любой Scanner.nextFoo метод (кроме nextLine сам).

Временное решение:

  • Либо положить Scanner.nextLine звоните после каждого Scanner.nextInt или же Scanner.nextFoo потреблять остаток этой строки, включая перевод строки

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Или, что еще лучше, прочитайте ввод через Scanner.nextLine и преобразовать ваши данные в нужный вам формат. Например, вы можете преобразовать в целое число, используя Integer.parseInt(String) метод.

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

Проблема в методе input.nextInt() - он только читает значение int. Поэтому, когда вы продолжаете чтение с помощью input.nextLine(), вы получаете клавишу ввода "\n". Поэтому, чтобы пропустить это, вы должны добавить input.nextLine(). Надеюсь, это должно быть ясно сейчас.

Попробуйте это так:

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();

Это потому, что когда вы вводите номер, а затем нажмите Enter, input.nextInt() потребляет только число, а не "конец строки". когда input.nextLine() выполняется, он потребляет конец строки, все еще находящийся в буфере с первого ввода.

Вместо этого используйте input.nextLine() незамедлительно после input.nextInt()

Кажется, есть много вопросов по этому вопросу с java.util.Scanner, Я думаю, что более читаемым / идиоматическим решением было бы позвонить scanner.skip("[\r\n]+") удалить любые символы новой строки после вызова nextInt(),

РЕДАКТИРОВАТЬ: как @PatrickParker отметил ниже, это приведет к бесконечному циклу, если пользователь вводит любой пробел после числа. Смотрите их ответ для лучшего шаблона для использования с пропустить: /questions/40727162/formatirovanie-strok-v-klasse-java-scanner/40727189#40727189

Вещи, которые вам нужно знать:

  • текст, представляющий несколько строк, также содержит непечатаемые символы между строками (мы называем их разделителями строк), например

    • возврат каретки (CR - в строковых литералах, представленных как "\r")
    • перевод строки (LF - в строковых литералах, представленных как "\n")
  • когда вы читаете данные с консоли, это позволяет пользователю вводить свой ответ, а когда он это делает, ему необходимо каким-то образом подтвердить этот факт. Для этого пользователю необходимо нажать клавишу "ввод"/"возврат" на клавиатуре.

    Важно то, что этот ключ помимо обеспечения помещения пользовательских данных на стандартный ввод (представлен System.in который читает Scanner) также отправляет OS-зависимые разделители строк (как для Windows \r\n) после этого.

    Поэтому, когда вы спрашиваете пользователя о значении, как age, а пользователь вводит 42 и нажимает ввод, стандартный ввод будет содержать "42\r\n",

проблема

Scanner#nextInt (и другие Scanner#nextType методы) не позволяет сканеру использовать эти разделители строк. Это будет читать их из System.in (как иначе Сканер узнал бы, что больше нет цифр от пользователя, которые представляют age значение, которое стоит перед пробелом?), который удалит их из стандартного ввода, но он также кеширует эти разделители строк внутри. Нам нужно помнить, что все методы Scanner всегда сканируют, начиная с кэшированного текста.

Сейчас Scanner#nextLine() просто собирает и возвращает все символы, пока не найдет разделители строк (или конец потока). Но поскольку разделители строк после считывания числа из консоли сразу же обнаруживаются в кэше сканера, он возвращает пустую строку, то есть сканер не смог найти какой-либо символ перед этими разделителями строк (или концом потока).
КСТАТИ nextLine также потребляет эти разделители строк.

Решение

Поэтому, когда вы хотите запросить номер, а затем и всю строку, избегая этой пустой строки в результате nextLine, или

  • использовать разделитель строк слева nextInt из кеша сканеров
  • не использовать nextInt (ни nextили любой nextTYPE методы) вообще. Вместо этого прочитайте все данные построчно, используя nextLine и анализировать номера из каждой строки (при условии, что одна строка содержит только одно число) для правильного типа, как int с помощью Integer.parseInt,

Кстати: Scanner#nextType методы могут пропускать разделители (по умолчанию все пробелы, такие как табуляция, разделители строк), включая те, которые кэшируются сканером, пока они не найдут следующее значение без разделителя (токен). Благодаря этому для ввода, как "42\r\n\r\n321\r\n\r\n\r\nfoobar" код

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

сможет правильно назначить num1=42num2=321name=foobar,

Это происходит потому, что input.nextInt(); не захватывает новую строку. вы могли бы сделать как другие предложенные, добавив input.nextLine(); под.
В качестве альтернативы вы можете сделать это в стиле C# и проанализировать nextLine в целое число следующим образом:

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

Делать это работает так же хорошо, и это экономит вам строку кода.

Вместо input.nextLine() использование input.next(), Это должно решить проблему.

Модифицированный код:

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();
}

Если вы хотите прочитать как строки, так и целые числа, решение состоит в том, чтобы использовать два сканера:

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();

Если вы хотите сканировать ввод быстро, не путаясь с методом класса сканера nextLine (), используйте для этого пользовательский сканер ввода.

Код:

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;
    }

}

Преимущества:

  • Сканирует ввод быстрее, чем BufferReader
  • Уменьшает сложность времени
  • Сбрасывает буфер для каждого следующего ввода

Методы:

  • scanChar () - сканировать один символ
  • scanInt () - сканирует целочисленное значение
  • scanLong () - сканировать длинное значение
  • scanString () - сканирует строковое значение
  • scanDouble () - сканировать двойное значение
  • scanInt(int[] array) - сканирует полный массив (целое число)
  • scanLong (long [] array) - сканирует полный массив (Long)

Использование:

  1. Скопируйте данный код под свой код Java.
  2. Объект инициализации для данного класса

ScanReader sc = new ScanReader(System.in); 3. Импортируйте необходимые классы:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Бросьте IOException из вашего основного метода для обработки Exception 5. Используйте предоставленные методы. 6. Наслаждайтесь

Пример:

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....

Чтобы избежать проблемы, используйте nextLine(); незамедлительно после nextInt(); как это помогает в очистке буфера. Когда вы нажимаете ENTER nextInt(); не захватывает новую строку и, следовательно, пропускает Scanner код позже.

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

sc.nextLine() лучше по сравнению с анализом ввода. Потому что производительность будет хорошей.

Я думаю, что я довольно поздно на вечеринку..

Как уже говорилось, звонит input.nextLine() после получения значения int решит вашу проблему. Причина, по которой ваш код не работал, заключалась в том, что больше нечего было хранить из вашего ввода (где вы вводили int) в string1, Я просто пролью немного света на всю тему.

Рассмотрим nextLine() как нечетный среди методов nextFoo() в классе Scanner. Давайте рассмотрим небольшой пример. Допустим, у нас есть две строки кода, подобные приведенным ниже:

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

Если мы введем значение ниже (в виде одной строки ввода)

54 234

Ценность нашего firstNumber а также secondNumber переменные становятся 54 и 234 соответственно. Причина, по которой это работает таким образом, заключается в том, что новый перевод строки (т.е. \ n) НЕ генерируется автоматически, когда метод nextInt() принимает значения. Он просто берет "следующий int" и движется дальше. То же самое относится и к остальным методам nextFoo(), за исключением nextLine().

nextLine() генерирует новый перевод строки сразу после получения значения; это то, что @RohitJain означает, говоря, что новый перевод строки "потребляется".

Наконец, метод next() просто берет ближайшую строку без генерации новой строки; это делает этот метод предпочтительным для получения отдельных строк в одной и той же строке.

Я надеюсь, что это помогает.. Веселое кодирование!

если я ожидаю непустого ввода

public static Function<Scanner,String> scanLine = (scan -> {
    String s = scan.nextLine();
    return( s.length() == 0 ? scan.nextLine() : s );
  });


используется в приведенном выше примере:

System.out.println("Enter numerical value");    
int option = input.nextInt(); // read numerical value from input

System.out.println("Enter 1st string"); 
String string1 = scanLine.apply( input ); // read 1st string
System.out.println("Enter 2nd string");
String string2 = scanLine.apply( input ); // read 2nd string
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);
    }

В одном из моих вариантов использования у меня был сценарий чтения строкового значения, которому предшествовала пара целочисленных значений. Мне пришлось использоватьцикл for / while для чтения значений. И ни одно из приведенных выше предложений в данном случае не сработало.

С помощью input.next() вместо того input.nextLine()исправил проблему. Надеюсь, это может быть полезно для тех, кто имеет дело с подобным сценарием.

Используйте 2 объекта сканера вместо одного

Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");    
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();

Как nextXXX() методы не читаются newline, Кроме nextLine(). Мы можем пропуститьnewline после прочтения любого non-string ценность (int в этом случае) с помощью scanner.skip() как показано ниже:

Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(x);
double y = sc.nextDouble();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(y);
char z = sc.next().charAt(0);
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(z);
String hello = sc.nextLine();
System.out.println(hello);
float tt = sc.nextFloat();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(tt);

Используйте этот код, он решит вашу проблему.

System.out.println("Enter numerical value");    
int option;
option = input.nextInt(); // Read numerical value from input
input.nextLine();
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)

Чтобы решить эту проблему, просто создайте scan.nextLine(), где scan - это экземпляр объекта Scanner. Например, для объяснения я использую простую задачу HackerRank.

      package com.company;
import java.util.Scanner;

public class hackerrank {
public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    int i = scan.nextInt();
    double d = scan.nextDouble();
    scan.nextLine(); // This line shall stop the skipping the nextLine() 
    String s = scan.nextLine();
    scan.close();



    // Write your code here.

    System.out.println("String: " + s);
    System.out.println("Double: " + d);
    System.out.println("Int: " + i);
}

}

Это очень простая проблема для начинающих программистов в java. С той же проблемой я столкнулся, когда начал java (самоучка). На самом деле, когда мы берем ввод целочисленного типа данных, он считывает только целочисленное значение и оставляет символ newLine(\n), и эта строка (т.е. оставленная новой строкой целочисленным динамическим вводом) создает проблему, когда мы пытаемся получить новый ввод. например. Например, если мы возьмем целочисленный ввод, а затем попытаемся принять строковый ввод.

      value1=sc.nextInt();
value2=sc.nextLine();

значение2 будет автоматически считывать символ новой строки и не будет принимать пользовательский ввод.

Решение: просто нам нужно добавить одну строку кода, прежде чем принимать следующий пользовательский ввод, т.е.

      sc.nextLine();

или же

      value1=sc.nextInt();
sc.nextLine();
value2=sc.nextLine();

Примечание: не забудьте закрыть Сканер во избежание утечки памяти;

nextLine() будет читать ввод непосредственно как пустую строку, не дожидаясь текста, простое решение, добавив дополнительный сканер для использования пустой строки

      System.out.println("Enter numerical value");    
int option;
option = input.nextInt(); // Read numerical value from input
input.nextLine();
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)

Проблема в методе input.nextInt() - он считывает только значение int. Поэтому, когда вы продолжите чтение с помощью input.nextLine(), вы получите клавишу Enter "\n". Чтобы пропустить это, вам нужно добавить input.nextLine(). Надеюсь, теперь это должно быть ясно.

Попробуйте вот так:

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();
       Scanner scan = new Scanner(System.in);
    int i = scan.nextInt();
    scan.nextLine();//to Ignore the rest of the line after  (integer input)nextInt()
    double d=scan.nextDouble();
    scan.nextLine();
    String s=scan.nextLine();
    scan.close();
    System.out.println("String: " + s);
    System.out.println("Double: " + d);
    System.out.println("Int: " + i);

Используйте класс BufferedReader для ввода строки, это не создаст проблем

Мое тестирование дало те же результаты, что и Prine, однако я подумал о довольно простом обходном пути:

С помощью BufferedReader#nextLine()где бы вы Scanner#readLine(), избегает этой ошибки. Вы даже можете написать свою собственную оболочку Scanner, чтобы переопределить функцию readLine Scanner с помощью функции BufferedReader nextLine.

Почему бы не использовать новый сканер для каждого чтения? Как ниже. При таком подходе вы не столкнетесь со своей проблемой.

int i = new Scanner(System.in).nextInt();
Другие вопросы по тегам