Win a copy of Event Streams in Action this week in the Java in General 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
  • Devaka Cooray
  • Liutauras Vilda
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Paul Clapham
  • Knute Snortum
  • Rob Spoor
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Piet Souris
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Frits Walraven
  • Ganesh Patekar

Scanner exercise solution. Why did I need to create a new Scanner object here to get it to work?

 
Ranch Hand
Posts: 283
5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm working through an online MOOC Java class and I'm on Week 9 , exercise 21 ( https://materiaalit.github.io/2013-oo-programming/part2/week-9/ ).   I figured a solution , it wasn't as nice as the solution provided but I'm get what the solution did and I'm trying to learn from it.

However I'm also trying to understand why my solution ultimately required me to create a new Scanner object each time to get it to work?  The first Printer class below is what finally worked.  The second Printer class was my first attempt which didn't work .
The Main class was just to test it.

My theory as to why my first attempt ( the second Printer class ) didn't work is because the methods hasNextLine() already went through the Scanner object once when the  printLinesWhichContain() method was called to search for Väinämöinen ( printer.printLinesWhichContain("Väinämöinen"); )   so it doesn't loop back over the scanner object again even though the printLinesWhichContain() method is called again?












This didn't work .  Was my first try with the exercise.



 
Marshal
Posts: 65056
247
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If your method fails to read the file, don't catch the exception. Declare it with a throws clause and let the calling method deal with it. Avoid saying throws Exception or catching plain simple Exception if you can be more specific about the kind of exception (you know it will be a file not found exception).
Don't use return; like that. Actually your return; doesn't do anything that wouldn't happen anyway.
If you are reading files, don't make the Scanner a field. Make it a local variable, Create the Scanner object with try with resources(←read this link before using it). You aren't closing the Scanner, which means there is a risk that the file handle will remain “in use”, making the file unavailable for further reading. You must therefore close the Scanner, in which case it can't be used again. Try with resources does all the closing for you.
 
Saloon Keeper
Posts: 6042
58
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

You have a disconnect between hasNext() and nextLine(). hasNext() may return true even if there is no "line". You want hasNextLine().
 
Campbell Ritchie
Marshal
Posts: 65056
247
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Not quite convinced. You will get true from hasNextLine() even if the next line is empty, so hasNextLine() might only be reacting to the presence o a line end sequence. In which case hasNext() will return false. If there is a “next” following the current “cursor position,” that constitutes part of a line so (I think) nextLine() will read that as the next line. I think the only circumstance where that will fail is if the last line doesn't end with a line end sequence.
 
Lisa Austin
Ranch Hand
Posts: 283
5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:If your method fails to read the file, don't catch the exception. Declare it with a throws clause and let the calling method deal with it. Avoid saying throws Exception or catching plain simple Exception if you can be more specific about the kind of exception (you know it will be a file not found exception).
Don't use return; like that. Actually your return; doesn't do anything that wouldn't happen anyway.
If you are reading files, don't make the Scanner a field. Make it a local variable, Create the Scanner object with try with resources(←read this link before using it). You aren't closing the Scanner, which means there is a risk that the file handle will remain “in use”, making the file unavailable for further reading. You must therefore close the Scanner, in which case it can't be used again. Try with resources does all the closing for you.



Thanks.  The Try with Resources worked when I reworked the solution.  Regarding the need to close the scanner.  At one point I asked about a different exercise regarding scanner and was told not to close the scanner .  Maybe it was the specific situation that was being refereed to but do you think you can help me understand why one exercise I would be told not to and then this one I'm being told to do so?    Here is the post I'm talking about POST.

Thank you for the advice about not catching the exception.  The MOOC lesson Try/Catch but it was probably just to try and get the concept across so it's good to have that information.

 
Carey Brown
Saloon Keeper
Posts: 6042
58
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The advice about not closing a Scanner is specific to one scenario, the case in which you create a new Scanner from System.in.

Also note that there should only ever be one Scanner created from System.in. Do not open multiple Scanners from System.in nor create them in a loop.
 
Lisa Austin
Ranch Hand
Posts: 283
5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Carey Brown wrote:The advice about not closing a Scanner is specific to one scenario, the case in which you create a new Scanner from System.in.

Also note that there should only ever be one Scanner created from System.in. Do not open multiple Scanners from System.in nor create them in a loop.



Okay got it.  
Regarding the advice about not opening multiple Scanners from System.in or creating them in a loop.  Are you referring to when I did  (reader.hasNext()) for example.  Is that what you are referencing?  
 
Campbell Ritchie
Marshal
Posts: 65056
247
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Lisa Austin wrote:. . . Are you referring to when I did  (reader.hasNext()) for example. . . .

No. This is what you should do:-My ideal is to create a utility class, with static methods for different kinds of input. Note this has one Scanner instance, which is kept open for the lifetime of the current JVM.
You want to avoid this sort of code:-As long as you are only using one Thre‍ad, you only need one Scanner per application, so there is no point in creating more instances.
 
Lisa Austin
Ranch Hand
Posts: 283
5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:

Lisa Austin wrote:. . . Are you referring to when I did  (reader.hasNext()) for example. . . .

No. This is what you should do:-

}[/code]As long as you are only using one Thre‍ad, you only need one Scanner per application, so there is no point in creating more instances.




Ah got it.  Thank You very much.  
 
Campbell Ritchie
Marshal
Posts: 65056
247
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's  pleasure

Scanners aren't thread‑safe; I have tried and failed to make my utility class thread‑safe. By the time you are multi‑threading your code, you will want an input mechanism other than System.in.
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!