• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Liutauras Vilda
  • Campbell Ritchie
  • Tim Cooke
  • Bear Bibeault
  • Devaka Cooray
Sheriffs:
  • Jeanne Boyarsky
  • Knute Snortum
  • Junilu Lacar
Saloon Keepers:
  • Tim Moores
  • Ganesh Patekar
  • Stephan van Hulst
  • Pete Letkeman
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Ron McLeod
  • Vijitha Kumara

Should I routinely call nextLine() on a Scanner object?  RSS feed

 
Marshal
Posts: 60065
188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thread in reply to this post, where,

William Varner wrote:Also, do y'all recommend doing a "sc.nextLine()" after scanning in an int? I was taught that this was very important.

No, I don't recommend that. There is one situation where a nestLine() call is needed. See this old post of mine.
The nextLine() method is not well documented in many places; some books suggest it reads the next line, but the link I gave you makes it clear that isn't correct. It returns the remainder of the current line; if the current line contains something which has been read, there is a risk that nextLine() will read an empty line from the rest of the line, and even better, the following line, which you actually want to read, is read as something else causing (if you are lucky) an exception, or (if you are unlucky) putting the information into the wrong locations in your program. So, as you will see from the old post, you need to call nxxtLine() after nextSomethingElse() and before the nextLine() call that you actually want.
If you call nextLine() after every nextInt() call, you will slow down execution because you are using twice as many calls and you will lose the flexibility of Scanner. It is possible to write a line like this:-
123 456 789
and call it with any three calls to read numbers, in any order. If you follow the first call with nextLine(), you will lose the 456 789 part. Example
Actually, if you are using the keyboard, I think that is all wrong too. What I did was to write a utility class, so I can writeBut my utility class only works for keyboard input. It is so written that is never throws an input mismatch exception.
 
Marshal
Posts: 6008
415
BSD
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Surprisingly big amount of people are confused about scanner's functionality.

Here is how I was researching this area for myself in order to understand it.

Sample data:

- Let's omit Java ceremony and just assume we start from here:
- First thing to understand is, that default scanner's delimiter is a white space character.


1. Now we want to extract number 2. So we call:
And there is still more to read in this text string...


2. If we were to call:
That would return "heads", because that is the next token after the default delimiter (white space character) has been passed. If we were to call again same method, that would return "are" and so on...


2.1. If we were to call (right after the step 1):
That would return the rest of the current line (default delimiters aren't skipped), which ends right after the line separator "\n", excluding line separator itself, meaning, would return: " heads are better than 1."

That is what small part of documentation says:

JavaDocs of nextLine() wrote:* This method returns the rest of the current line, excluding any line
* separator at the end. The position is set to the beginning of the next
* line.


3. Having said that, there would be still some data left to read in the text string, and that would be: "CodeRanch.com is great."

4. Now, there are only few options left:
[option 1] either call in.next() (at most 3 times) so it would tokenize (based on default delimiters) and return from calls of in.next(): [1]CodeRanch.com [2]is [3]great.
[option 2] call simply in.nextLine() which would return: " CodeRanch.com is great." and again as documentation says, after such call would be:

JavaDocs of nextLine() wrote:* The position is set to the beginning of the next line.

Since there is nothing else to read, end of story, exception would be thrown attempting to read further.
[option 3] mix of these two above.

----
It is worth mentioning, that next() and nextLine() differ in that way, that next() tokenize based on default or set delimiter(s), while nextLine() ignores them and just reads the rest of the current line.

Quick example of next():

All tokens would be read by only 2 calls of next() method, because "\n" isn't part of default delimiter and I did not set it up as such (while for nextLine() "\n" would mean end of the current line):

1.
By printing that with print(), it would print (on separate lines):

2.

I think spending about 15-30 minutes trying to read in and print in various ways would eliminate most of confusion about the Scanner people have.
 
Saloon Keeper
Posts: 9213
177
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think you can compare a call to scanner.nextLine() to the following sequence of calls:
 
Saloon Keeper
Posts: 4735
52
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
THIS discussion was posted yesterday. It involved reading a record from a file laid out as 5 separate lines of input.  After each non-nextLine() call the OP put a call in to nextLine(). So, the very last item in a record was a double with a call to nextDouble() followed by a call to nextLine(). This worked for all the records except the last one because there was no new-line character following the last double, so it threw a NoSuchElementException.

So here we have another case where always adding a call to nextLine() causes a failure.
 
Sheriff
Posts: 5111
138
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm the outlier here.  For getting input from the keyboard, the only function I use from Scanner is nextLine().  This is for two reason.  One, I want to be able to detect when the user only presses <Enter>.  I use this behavior to enter default values.

    What is the meaning of the Universe? (default = 42):

The other is that if you use nextInt() or any of the other nextXxx() functions you can run into this problem:

    What is your age? 6e

Here the user has slipped and accidentally typed 6e instead of 64.  I don't want the program to accept 6 and leave e in the buffer.  I want the program to ask for the age again.

Campbell and I do agree on one thing: you really need to write a utility class to wrap Scanner (or maybe BufferedInput?).  Add prompting and validation and you have a handy class.  I call mine Inputer and it's freely available on my GitHub repo.
 
Campbell Ritchie
Marshal
Posts: 60065
188
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Knute Snortum wrote:. . . . I don't want the program to accept 6 and leave e in the buffer.  I want the program to ask for the age again. . . . .

It won't. It will throw an exception. If you want to avoid the exception, you need the loop which Rob Spoor taught me ages ago:-I have that method overloaded so as to accept different error messages for incorrect input. I also have the method overloaded to accept only values in a certain range, but you have to throw an illegal argument exception if !(max > min). I have not therefore worked out how to supply a default. Lines 21‑22 can be swapped.
There are various possibilities for reading a whole line; the following is one of them:-I have found no defence against people who use ctrl‑D/ctrl‑Z and close System.in. Eclipse users might wish to add a @SuppressWarnings annotation to line 6. I have not worked out how to make such a class threadsafe. The \u2019 escape is a posh apostrophe.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!