• Post Reply Bookmark Topic Watch Topic
  • New Topic

FYI: wrapper class for Scanner(System.in)  RSS feed

 
Carey Brown
Saloon Keeper
Posts: 3328
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There is a bad programming practice of creating a new Scanner object with System.in in every place you need to get some keyboard input. The correct way is to only ever create one new Scanner(System.in) object and pass it around or make it static.

Here is a utility class for doing this, wrapping the common Scanner methods with a private static Scanner object:

Including this class in your project then allows you to make calls like this:
 
Piet Souris
Master Rancher
Posts: 2044
75
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Nice Wrapper!

To all those unfortunates who did close System.in and who use an IDE: just rerun your program and all is fine again.

@Carey: I've seen you using quite some Patterns lately. Time to change your sig a little?    
 
Knute Snortum
Sheriff
Posts: 4281
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Perhaps this wasn't your concern, but this doesn't address the nextLine() after nextInt() problem.
 
Campbell Ritchie
Marshal
Posts: 56576
172
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are still risking an input mismatch exception. A long time ago, Rob Spoor taught me how you can avoid that exception altogether, with a loop:-That code won't throw an input mismatch exception.
You also would want a private constructor because that utility class shou‍ld never be instantiated. You can enhance those methods to return only values in a specified range. Other mehods can be written similarly. For nextBoolean(), you will get true from any input matching “true”, but case‑insensitive, but if you write anything else, 1234567890 or Carey (I think) it will interpret that as meaning false.
 
Carey Brown
Saloon Keeper
Posts: 3328
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Knute Snortum wrote:Perhaps this wasn't your concern, but this doesn't address the nextLine() after nextInt() problem.

I thought about that. My approach was to keep the logic as close as possible to a programs direct use of Scanner, which would include the warts.
 
Carey Brown
Saloon Keeper
Posts: 3328
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:You are still risking an input mismatch exception. A long time ago, Rob Spoor taught me how you can avoid that exception altogether, with a loop:-That code won't throw an input mismatch exception.
You also would want a private constructor because that utility class shou‍ld never be instantiated. You can enhance those methods to return only values in a specified range. Other mehods can be written similarly. For nextBoolean(), you will get true from any input matching “true”, but case‑insensitive, but if you write anything else, 1234567890 or Carey (I think) it will interpret that as meaning false.

Absolutely I need a private constructor. Good catch.

Good suggestion for a more robust method. I'll have to think about it a bit. My original thinking was to keep it as close to direct use of a Scanner object as possible. But this might make a lot of programs behave better.
 
Knute Snortum
Sheriff
Posts: 4281
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:You also would want a private constructor because that utility class shou‍ld never be instantiated.

What about a multiuser system?  Wouldn't having only one Scanner mean that users could clobber each other's buffers?
 
Knute Snortum
Sheriff
Posts: 4281
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Anyone interested in how I dealt with this problem can look at:

https://github.com/ksnortum/Inputer
 
Liutauras Vilda
Sheriff
Posts: 4925
334
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Knute Snortum wrote:Perhaps this wasn't your concern, but this doesn't address the nextLine() after nextInt() problem.

And that part could be handled using this method, nope? I think almost always this works, either you had nextInt() before or you didn't.
 
Carey Brown
Saloon Keeper
Posts: 3328
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Updated with private constructor.
 
Campbell Ritchie
Marshal
Posts: 56576
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Knute Snortum wrote:. . . What about a multiuser system? . . .
You would have one Scanner object per JVM, not one Scanner object per computer, but I don't know more about multiuser systems.
As I said, my version isn't thread‑safe, but it could be made thread‑safe.

It was Rob Spoor who taught me about that loop. I preferred to maintain the default delimiter, and would use a second Scanner object if it is ever necessary to use a different delimiter. Yes, nextInt() + nextLine() would work, but there is a subtle difference:-
  • 1: Passing "Sheriff: Campbell Ritchie" to next() followed by nextLine() returns "Sheriff:" and "Campbell Ritchie"
  • 2: Passing "Sheriff: Campbell Ritchie" to next() + nextLine() returns "Sheriff:Campbell Ritchie"
  • 3: Passing "Sheriff: Campbell Ritchie" to nextLine() returns "Sheriff: Campbell Ritchie"
  • I like Knute's validation which shows the input to the user and allows them to say whether it is correct . I have validation for ranges of numbers but never thought to use validation for names like that.
     
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Are multiple users and concurrency around standard input really a concern when it comes to this kind of thing? I can't think of any reason it would be. What am I missing?
     
    Campbell Ritchie
    Marshal
    Posts: 56576
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I can imagine scenarios where threading would be a problem, e.g. if you are reading similar input from multiple threads. I can't see that multiple users would be an issue unless they are trying to use the same terminal/command line.
     
    Knute Snortum
    Sheriff
    Posts: 4281
    127
    Chrome Eclipse IDE Java Postgres Database VI Editor
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Junilu Lacar wrote:Are multiple users and concurrency around standard input really a concern when it comes to this kind of thing? I can't think of any reason it would be. What am I missing?

    Probably nothing.  I keep forgetting that each user will have their own JVM.  I might change my Inputer class based on this.
     
    Don't get me started about those stupid light bulbs.
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!