I didn't understand the behavior of Java Scanner and .nextLine ().

The beginning of the matter

Write code like this in Java

Main1.java


import java.util.*;

/**
 * Created 2017/05/23.
 */

public class Main1 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}

Often in program contests 1: First receive the number input Receive more inputs for the number of times entered 2: 1 Input value of 3: 2 in various ways Because I needed a program like that Input the number of times → Write the input String in the form of storing in ArrayList However, the result of this execution is strange

Input value
2
a
b (cannot actually be entered)

Execution result
[, a]

A mysterious blank? I was in a situation where I was in, so I decided to investigate the cause ...

First of all, to understand the specifications of .nextLine ()

First, let's grasp the specifications with the reference https://docs.oracle.com/javase/jp/8/docs/api/java/util/Scanner.html#nextLine--

nextLine

public String nextLine() Advances the scanner to the current line and returns skipped input. This method returns the rest of the current line, excluding the last line delimiter. The position is set at the beginning of the next line. This method continues searching for the line delimiter in the input, so if the line delimiter does not exist, it may buffer all input that searches for lines to skip. Return value: Skipped lines exception: NoSuchElementException-if row not found IllegalStateException-if this scanner is closed


~~ Yeah, I don't know what you're talking about ~~ As a result of various investigations for the time being -.NextLine () also reads blanks (blank lines) I understood that But this time, I run into the question of where the blanks (blank lines) are coming from.

Examine the actual behavior one by one

To check by writing the source code while actually examining it (it is much faster to move your hands than to worry about your head) The order of the source code file names is out of order, but please think that this is the result of various trials. ~~ I can't read this with just the reference ... ~~

First, let's take a quick look at the behavior of Scanner and .nextLine ().

Behavior of Scanner and .nextLine ()

Main5

Main5.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 *The behavior of nextLine
 */
public class Main5 {
   public static void main(String[] args) {
      String word = "123 test";
      Scanner sc = new Scanner(word);
      String line = sc.nextLine();

      System.out.println(word);
      //Execution result:123 test
      System.out.println(line);
      //Execution result:123 test
   
   }
}
Execution result
123 test
123 test

This is very easy to understand

Main6 Next, try multiple scans

Main6.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main6 {
  public static void main(String[] args){
    String word = "123 test";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt(); 
    String line = sc.nextLine();

    System.out.println(word);
    //Execution result:123test

    System.out.println(num);
    //Execution result: 123
    
    System.out.println(line);
    //Execution result: test

  }
}

Execution result
123 test
123
 test

What I want to pay attention to here is the output result of line. If you do .nextLine (); after doing .nextInt (); in advance, the number part has already been read. You can see that only blank + test remains

So what if you do .nextLine () after reading everything? Let's try it!

Main7

Main7.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main7 {
  public static void main(String[] args){
    String word = "123 test";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt();
    String word2 = sc.next();
    
    //String line = sc.nextLine();
    //I get an error properly
    //Exception in thread "main" java.util.NoSuchElementException: No line found

    System.out.println(word);
    //Execution result:123test

    System.out.println(num);
    //Execution result: 123

    System.out.println(word2);
    //Execution result:test

    //System.out.println(line);
    //Execution result:Not executed in the first place due to the above error

  }
}
Execution result 1
123 test
123
test

Although it is written in the comment, if you uncomment .nextLine (); and execute it, an error will occur.

Execution result 2(.nextLine();Uncomment and run)
Exception in thread "main" java.util.NoSuchElementException: No line found
	at java.util.Scanner.nextLine(Scanner.java:1540)
	at Java.Nexts.Main7.main(Main7.java:15)

This does not reveal the truth ... It will return an error like "There is no line!" However, if you add a little, the error will disappear.

Main8

Main8.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main8 {
  public static void main(String[] args){
    String word = "123 test\n";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt();

    String word2 = sc.next();

    String line = sc.nextLine();
  
    System.out.println(word);//
    //Execution result:123test
    //
    //There is a space (line feed) above
    
    System.out.println(num);
    //Execution result: 123

    System.out.println(word2);
    //Execution result:test

    System.out.println(line);
    //Execution result: (Blank)
    //It's blank, but it's actually reading a blank line, so it doesn't mean that Line doesn't exist → it doesn't throw an error!
    //System here.out.println(line);It's very easy to understand if you run it with debugging!

  }
}
Execution result
123 test

123
test

Yes this is the truth Add the line feed code "\ n" at the String word. Then, after scanning up to word2, unlike Main7, line breaks will remain. String line = sc.nextLine (); reads as a line break (blank line) As a result, the line will contain an empty string.

This can be seen visually using the debug features of the IDE. nextline.png You can see that there is a "" in the line

So what was happening

Now you can finally see if the code in Main1 behaved strangely. 1: First, when entering a numerical value, after hitting 2 and pressing enter, "2 \ n" is entered in the sc contents. When scanning with 2: int num = sc.nextInt () ;, num = 2 is stored and the content of sc is only "\ n" 3: After starting the loop, String word = sc.nextLine (); reads the current remaining sc content "\ n" and Store in ary as an empty string 4: The contents of sc are empty, so read and store the new input "a" here. 5: At this point, the loop stops because the process is performed twice. 6: The contents of ary become [, a]

In conclusion -Scanner returns the value of the current location (the part where the contents remain) -.NextLine () also reads blank lines It was a problem that occurred in the combined technique of

Then how do you get the ideal movement?

The fundamental solution is to create two scanners That way, you won't have to read the debris when entering numbers.

Main4.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2017/05/25.
 *Feeling that the cause was finally understood
 */
public class Main4 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    Scanner sc2 = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc2.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
input
2
a
b
Execution result
[a, b]

It's perfect!

Also, if you know that the string you enter is not space separated You can get the same result just by using .next ()

Main2.java


import java.util.*;

/**
 * Created 2017/05/23.
 */
public class Main2 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc.next();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
input
2
a
b
Execution result
[a, b]

However, please note that the code of Main2 may behave unintentionally when you type a space-separated sentence.

2
a b c
Execution result
[a, b]

2017/5/25 postscript I got a smarter solution in the comments

Main9.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2017/05/25.
 *Get Qiita to teach you smarter ways
 */
public class Main9 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = Integer.parseInt(sc.nextLine());    //Integer.Once converted to a complete number using parseInt, it can be read by nextLine!
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
input
2
a
b
Execution result
[a, b]

First, .nextLine () treats the read result as a String type. for that reason int num = sc.nextLine(); If you write as it is ʻError: (13, 26) java: Incompatible type: Unable to convert java.lang.String to int: And type inconsistency, and cannot be stored in int num Howeverint num = Integer.parseInt(sc.nextLine()); By writing, the value read by.nextLine () can be converted to a numerical value, so it can be stored in ʻint num! This way of writing does not require multiple scanners In addition, it's like calling .nextLine () for each line entered, which makes the code very straightforward.

Impressions

~~ Java is troublesome ~~ Joking aside I want to enter → Scanner sc = new Scanner (System.in); I want to read line by line → .nextLine (); It is undeniable that there was a copy-like idea that you should use. This time, I understood well that I had an essential understanding of Scanner. There are still many things I don't understand about Java, so I would like to continue studying hard.

2018/01/19 When I read it again after a long time, I was worried about it, so I corrected one You don't have to make a new scanner, just scan the whitespace once and it will work fine.

ScanSample.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2018/01/19.
 *correction
 */
public class ScanSample {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    String blank = sc.nextLine();
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
input
2
a
b
Execution result
[a, b]

Recommended Posts

I didn't understand the behavior of Java Scanner and .nextLine ().
I compared the characteristics of Java and .NET
About next () and nextLine () of the Scanner class
I summarized the types and basics of Java exceptions
I tried to summarize the basics of kotlin and java
Java beginners briefly summarized the behavior of Array and ArrayList
[Java] I thought about the merits and uses of "interface"
I tried to summarize the methods of Java String and StringBuilder
About the operation of next () and nextLine ()
[day: 5] I summarized the basics of Java
[Java] [Spring] Test the behavior of the logger
I translated the grammar of R and Java [Updated from time to time]
[Java] Understand the difference between List and Set
By checking the operation of Java on linux, I was able to understand compilation and hierarchical understanding.
Difference between next () and nextLine () in Java Scanner
[Java] The confusing part of String and StringBuilder
I touched on the new features of Java 15
Try the free version of Progate [Java I]
I received the data of the journey (diary application) in Java and visualized it # 001
Summary of ToString behavior with Java and Groovy annotations
Please note the division (division) of java kotlin Int and Int
The comparison of enums is ==, and equals is good [Java]
[For beginners] Quickly understand the basics of Java 8 Lambda
Organizing the current state of Java and considering the future
Java language from the perspective of Kotlin and C #
Check the behavior of Java Intrinsic Locks with bpftrace
Java classes and instances to understand in the figure
[Note] Java Output of the sum of odd and even elements
behavior of didSet and willSet
Now, I understand the coordinate transformation method of UIView (Swift)
Understand the basics of docker
Command to check the number and status of Java threads
Understand the Singleton pattern by comparing Java and JavaScript code
What should I do after January 2019 regarding the Java payment issue and Java 8 end of support issue?
I tried JAX-RS and made a note of the procedure
[Java] I implemented the combination.
Advantages and disadvantages of Java
Java concurrency I don't understand
Understand the Iterator pattern by comparing Java and JavaScript code
I studied the constructor (java)
[Action View :: Missing Template] I didn't understand the meaning of the error statement, so I looked it up.
I didn't understand the meaning of injection such as DI or @Autowired, so I looked it up.
[Java] Various summaries attached to the heads of classes and members
I think I understand the reuse of cells, but I don't understand at all.
[Java] Get the dates of the past Monday and Sunday in order
I want to understand the flow of Spring processing request parameters
The story of not knowing the behavior of String by passing Java by reference
I want to return to the previous screen with kotlin and java!
I tried the input / output type of Java Lambda ~ Map edition ~
Read the first 4 bytes of the Java class file and output CAFEBABE
From fledgling Java (3 years) to Node.js (4 years). And the impression of returning to Java
I examined the concept of the process to understand how Docker works
I passed the Oracle Java Bronze, so I summarized the outline of the exam.
The behavior of JS running on `Java SE 8 Nashorn` suddenly changed
About the behavior of ruby Hash # ==
[Java] Delete the elements of List
I compared PHP and Java constructors
Understand the basic mechanism of log4j2.xml
[java8] To understand the Stream API
About fastqc of Biocontainers and Java
[Java version] The story of serialization