This week's book giveaway is in the Kotlin forum.
We're giving away four copies of Kotlin Cookbook and have Ken Kousen on-line!
See this thread for details.
Win a copy of Kotlin Cookbook this week in the Kotlin forum!
  • 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:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
Sheriffs:
  • Junilu Lacar
  • Knute Snortum
  • Henry Wong
Saloon Keepers:
  • Ron McLeod
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Frits Walraven
  • Joe Ess
  • salvin francis

Scanner class question

 
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

I have skimmed through the documentation on the Scanner class as well as other resources and still can't figure this out. The exercise is to write a program that reads four integer numbers from one line and prints them each on a new line. In the input line numbers are separated by one or more spaces.

My code:


If I input '1 2 3 4 ' It is returning:
3
2
1

As a matter of fact, it seems like no matter what code I put in, I get that output. I don't understand what I'm doing wrong.
Thanks
 
Saloon Keeper
Posts: 6619
62
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
println(reads) prints the results of reads.toString() which could be anything that the designers of the Scanner class chose. I presume it is totally unrelated to the input because that would require processing the input stream which would mean that it would no longer be there for your program to process. Basically, this doesn't do what you think it does.

You don't need to set up a delimiter, your requirements already match the default delimiter.

You'll need to be calling reads.nextInt() a few times.
 
Sheriff
Posts: 6569
176
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't think that code produces that output.  I think it will print a long string describing the Scanner object.

What I would try is to use the Scanner nextLine() method to read a String from System.in.  Then figure out a way to break your String into pieces, then print them.
 
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Khayla Matthews wrote:. . . numbers are separated by one or more spaces. . . .

No, it isn't. It is separated by comma or spaces(s), because that is what you wrote as your delimiter. Please go back to the Scanner documentation, where you will find that the default delimiter probably does what you want.
Knute is right: this is what I got as an output from your line 5 on JShell (JDK13):-

java.util.Scanner[delimiters=[,\s+]][position=0][match valid=false][need input=false][source closed=false][skipped=false][group separator=\,][decimal separator=\.][positive prefix=][negative prefix=\Q-\E][positive suffix=][negative suffix=][NaN string=\QNaN\E][infinity string=\Q∞\E]

Please explain exactly how you are running that code because I can't see how you can get 3 2 1 as an output.
I think I would, like Carey, use nextInt() four times, but that sounds like iffy, repetitious, code.
 
Khayla Matthews
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the feedback and the help.

I can confirm this is the output I'm getting (see screenshot). I am going to take what you all said and try again.
codeexample.JPG
[Thumbnail for codeexample.JPG]
 
Khayla Matthews
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Aha! I caught the issue. IntelliJ was running a previous, but similar, class I had written that requires input.
 
Khayla Matthews
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Finally gave up and just looked at the solution. Glad I did because I never would have gotten that. It was so simple, but I see now I misunderstood how nextInt() works.

much thanks to everyone patiently helping.
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Khayla Matthews wrote:. . . a previous, but similar, class . . .

That shows how you can confuse yourself by creating two classes with such similar names.

. . . looked at the solution. Glad I did . . .

I am not glad; it means you haven't worked out the solution yourself and you aren't learning as much as you could have. And please show us what they suggested as an answer.
 
Khayla Matthews
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I appreciate your candor. and yes, lesson learned!

It suggested a very simple solution. and you're right I'm not getting it, still working on exercises using scanner and it is taking forever.

 
Ranch Foreman
Posts: 240
5
Eclipse IDE C++ Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
if that was the official solution, it's a horrible way to teach anyone. nobody would want to write code like that in the real world!

i think you can do this with a while loop, something like:
 
Khayla Matthews
Greenhorn
Posts: 23
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Update: I think I'm finally getting somwewhere with this. I was able to finish the last couple Scanner class exercises relatively quickly and unaided.
Thanks again for the help everyone!

I know some people were saying they used loops to solve it, but I couldn't wrap my mind around how and the official answer didn't include it. I'm going to keep reading up on Scanner though. Hopefully if I reread some things even more will sink in.
 
Carey Brown
Saloon Keeper
Posts: 6619
62
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

S Fox wrote:if that was the official solution, it's a horrible way to teach anyone. nobody would want to write code like that in the real world!

i think you can do this with a while loop, something like:


I think it would be better to use hasNextInt().
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

S Fox wrote:. . . nobody would want to write code like that in the real world!

Agree; look at that repeated code.

i think you can do this with a while loop . . .

Yes, you can use a loop, but there is a serious problem with the loop you wrote. I am challenging you to find it. I would probably use a for loop, or you could follow Carey's suggestion.
 
S Fox
Ranch Foreman
Posts: 240
5
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
here's why i think my loop was wrong:
the code i wrote would print the first int and then loop forever doing nothing. because hasNext() will cause everything to be seen as a token, and because i don't print all tokens the first whitespace char i encounter will become stuck in the input buffer and i won't be able to advance past it.

the way to fix it is to change the looping condition as Carey says, or i could just print reads.next() which will cause every token to print. once all tokens are printed the input buffer is empty so hasNext() returns false, this allows the while loop to exit.

is that right?
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That sounds very complicated and I don't think you have understood the problem. You won't get stuck on whitespace because a Scanner always watches for its delimiter.
The normal System.in implicitly always has a “next token”, so hasNext() always returns true, so you now have an infinite loop. You can only get out of that loop by causing something to throw an exception, e.g. by passing a non‑int (this exception) or by closing System.in (this exception). Closing System.in is worse because even if you catch the exception, you can't reopen it. Carey's suggestion gets you out of the infinite loop problem; it terminates at the first non‑int. My suggestion would get you a loop running four times; again not an infinite loop.

I would consider putting the four ints into an int[]. Note alliterative writing.
 
S Fox
Ranch Foreman
Posts: 240
5
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
i learned how scanners work when i learned C, i rarely use them and i didn't re-learn them for java. why would java intentionally lie that there is something next if there really isn't? i think that in C when the input buffer is empty a while loop like this will exit properly.
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

S Fox wrote:. . . when i learned C . . . i didn't re-learn them for java.

That's a big mistake. Thanking that C works the same as Java® is another mistake.

why would java intentionally lie that there is something next if there really isn't? . . .

What makes you think there is any lying involved? There is a next token, but it is still in your fingers. If you read the documentation, you will see that some of its methods block and wait for input. It is waiting for input, and assumes that there will be more input as long as there is an input stream.

None of those things applies to a file. A file always has an end, and hasNext() returns false when the end of the file is reached.
 
S Fox
Ranch Foreman
Posts: 240
5
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
but really there's a difference between "already has a next token" and "there might eventually be a next token" that's why it's lying. because if there's nothing currently in the input buffer, it has no next token to act upon.

if (x == y) do something... well it might eventually be true, should i just go ahead and evaluate it as true right now even though it's really false?

so to me it's weird they designed it like that.
 
Sheriff
Posts: 14622
243
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Given this code:

There is at least one case I know where hasNext() on a Scanner(System.in) will return false: When you type Ctrl+D. That will signal the end of input and terminate the loop normally. Ctrl+C will terminate the program abnormally so line 7 won't be executed. The point being that there are at least two ways to get out of this "infinite loop."

I don't agree with characterizing the behavior of hasNext() with a Scanner(System.in) as "lying." The behavior can arguably be confusing but given the variety of types of input streams you can have, I don't think it's entirely inconsistent with what the documentation says. It's just a matter of understanding the behavior and having the correct expectations.
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

S Fox wrote:. . . "already has a next token" and "there might eventually be a next token" . . .

It is the difference between intent (optmiistic prediction) and final outcome (pessimistic prediction). It is taken optmiisticallly to mean, “there might eventually be a next token.”

that's why it's lying. . . .

No, it is you interpreting it in a way different from what its make intended. If I say, “I'll go out and have some beer,” that is true when I leave home. If I fall over and break my leg, or get there and find they have run out of beer, I shan't drink any beer. But that doesn't make my original statement incorrect, or even inaccurate.

so to me it's weird they designed it like that.

You are using somebody else's product, so you will have to use it as they designed it. But they didn't document its behaviour at all well, as Winston Gutkowski has pointed out before.
If you want something behaving differently, you might have to write it yourself.

Junilu Lacar wrote:. . . When you type Ctrl+D. That will signal the end of input and terminate the loop normally. . . .

That is what I meant about closing System.in, something I don't like to encourage. But maybe OP should try ctrl‑D (I think you use ctrl‑Z on Windows®) to see what happens. The loop doesn't wait on while (myScanner.hasNext()) ..., but on myScanner.nextInt(); so it doesn't terminate normally. It terminates by throwing an exception.
 
Junilu Lacar
Sheriff
Posts: 14622
243
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:The loop doesn't wait on while (myScanner.hasNext()) ..., but on myScanner.nextInt(); so it doesn't terminate normally. It terminates by throwing an exception.


That's not consistent with the behavior I see when I run this variation of the code on my Mac:

This code will also block and wait for input. If I just press CTRL+D, the program terminates normally.

EDIT: Running this variation, it's clear to me that hasNext() is blocking, not next():

Result (bold text are things I typed in):

$ java Foo.java
at hasNext()
CTRL+D
End of input

$ java Foo.java
at hasNext()
foo
at next()
foo
End of input
 
Campbell Ritchie
Marshal
Posts: 67050
255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It would appear I have been mistaken; the documentation says hasNext() blocks, not next(). But every time I have tried that, I have had a no such element exception.
 
We should throw him a surprise party. It will cheer him up. We can use this tiny ad:
Java file APIs (DOC, XLS, PDF, and many more)
https://products.aspose.com/total/java
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!