首页 文章

使用next()或nextFoo()后,Scanner正在跳过nextLine()?

提问于
浏览
526

我正在使用 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() 都按我希望的那样执行 .

14 回答

  • -2

    如果要读取字符串和整数,解决方案是使用两个扫描程序:

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

    那是因为Scanner.nextInt方法没有读取通过按"Enter,"创建的输入中的换行符,因此在读取该换行符后返回Scanner.nextLine的调用 .

    Scanner.next()之后使用 Scanner.nextLine 或任何 Scanner.nextFoo 方法( nextLine 本身除外)时,您将遇到类似的行为 .

    Workaround:

    • 在每个 Scanner.nextIntScanner.nextFoo 之后调用 Scanner.nextLine 来消耗该行的其余部分,包括换行符
    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();
    
  • 623

    问题出在 input.nextInt() 方法 - 它只读取int值 . 因此,当您继续使用input.nextLine()读取时,您会收到"\n" Enter键 . 所以要跳过这个你必须添加 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();
    
  • 26

    这是因为当您输入数字然后按Enter键时, input.nextInt() 仅消耗该数字,而不是"end of line" . 当 input.nextLine() 执行时,它会从第一个输入中消耗仍然在缓冲区中的"end of line" .

    而是在 input.nextInt() 之后立即使用 input.nextLine()

  • 18

    java.util.Scanner 似乎有很多关于这个问题的问题 . 我认为更可读/惯用的解决方案是在调用 nextInt() 之后调用 scanner.skip("[\r\n]+") 删除任何换行符 .

    编辑:正如下面提到的@PatrickParker,如果用户在数字后输入任何空格,这将导致无限循环 . 查看他们的答案以获得更好的模式以使用skip:https://stackoverflow.com/a/42471816/143585

  • 4

    这样做是因为 input.nextInt(); 不捕获换行符 . 你可以通过在下面添加 input.nextLine(); 来像其他人那样做 .
    或者,您可以使用C#样式并将nextLine解析为整数,如下所示:

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

    这样做也很有效,它为您节省了一行代码 .

  • 177

    你需要知道的事情:

    • 表示几行的文本也包含行之间的不可打印字符(我们称之为行分隔符)之类的

    • 回车(CR - 在字符串文字中表示为 "\r"

    • 换行(LF - 在字符串文字中表示为 "\n"

    • 当您从控制台读取数据时,它允许用户键入他的响应,当他完成后,他需要以某种方式确认这一事实 . 为此,用户需要按键盘上的"enter" / "return"键 .

    重要的是,除了确保将用户数据放置到标准输入(由 System.in 表示,由 Scanner 表示)之外,此键还会发送OS依赖行分隔符(如Windows \r\n ) .

    因此,当您向用户询问 age 之类的值,并且用户类型42并按Enter键时,标准输入将包含 "42\r\n" .

    问题

    Scanner#nextInt (和其他 Scanner#nextType 方法)不允许扫描程序使用这些行分隔符 . 它会从 System.in 读取它们(扫描器怎么会知道用户没有更多的数字表示 age 值而不是面对空格?)这将从标准输入中删除它们,但是 it will also cache those line separators internally . 我们需要记住的是,所有Scanner方法始终都是从缓存的文本开始扫描的 .

    现在 Scanner#nextLine() 只是收集并返回所有字符,直到找到行分隔符(或流的结尾) . 但是,由于在扫描程序的缓存中立即找到从控制台读取数字后的行分隔符,它会返回空字符串,这意味着扫描程序无法在这些行分隔符(或流结束)之前找到任何字符 .
    BTW nextLine 也消耗那些行分隔符 .

    解决方案

    因此,当您想要求数字然后是整行时,同时避免由于 nextLine 而导致的空字符串

    • 使用 nextInt 从扫描程序缓存中消耗行分隔符

    • 调用 nextLine

    • 或通过调用 skip("\\R") 让扫描仪跳过与 \R 匹配的部分,表示行分隔符(有关 \R 的更多信息:https://stackoverflow.com/a/31060125

    • 根本不使用 nextInt (也不是 next 或任何 nextTYPE 方法) . 而是使用 nextLine 逐行读取整个数据并从每一行解析数字(假设一行只包含一个数字)到正确的类型,如 int via Integer.parseInt .


    BTWScanner#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=42 num2=321 name=foobar .

  • 6

    而不是 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();
    }
    
  • 67

    为避免此问题,请在 nextInt(); 之后立即使用 nextLine(); ,因为它有助于清除缓冲区 . 按 ENTERnextInt(); 不捕获新行,因此稍后会跳过 Scanner 代码 .

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

    如果要快速扫描输入而不混淆Scanner类的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) - 扫描完成数组(长)

    用法:

    • 复制Java代码下面的Given Code .

    • 给定类的初始化对象

    ScanReader sc = new ScanReader(System.in); 3.导入必要的类:

    import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4.从main方法抛出IOException以处理异常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....
    
  • 4

    与解析输入相比, sc.nextLine() 更好 . 因为表现明智,所以会很好 .

  • 1

    我想我参加派对的时间已经很晚了..

    如前所述,在获取int值后调用 input.nextLine() 将解决您的问题 . 您的代码无法正常工作的原因是因为没有其他内容可以从您的输入(您输入int的位置)存储到 string1 中 . 我只是对整个主题稍微透露一点 .

    将nextLine()视为Scanner类中nextFoo()方法中的奇数 . 让's take a quick example.. Let'说我们有两行代码,如下所示:

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

    如果我们输入下面的值(作为单行输入)

    54 234

    我们的 firstNumbersecondNumber 变量的值分别变为54和234 . 这样工作的原因是因为当nextInt()方法接受值时自动生成新的换行符(即\ n) IS NOT . 它只需要"next int"并继续前进 . 除了nextLine()之外,其他nextFoo()方法也是如此 .

    nextLine()在获取值后立即生成新换行符;这就是@RohitJain所说的新线路被“消耗”的意思 .

    最后,next()方法只需要最近的String without 生成一个新行;这使得这是在同一行中获取单独字符串的优先方法 .

    我希望这有帮助..快乐编码!

  • 6
    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);
        }
    
  • 6

    为什么不在每次阅读时使用新的扫描仪?如下 . 使用这种方法,您将无法面对您的问题 .

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

相关问题