• 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 Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Devaka Cooray
  • Tim Cooke
Sheriffs:
  • Rob Spoor
  • Liutauras Vilda
  • paul wheaton
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
  • Piet Souris
Bartenders:
  • Stephan van Hulst

FYI: wrapper class for Scanner(System.in)

 
Saloon Keeper
Posts: 10920
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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:
 
Saloon Keeper
Posts: 5546
213
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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?    
 
Sheriff
Posts: 7125
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Perhaps this wasn't your concern, but this doesn't address the nextLine() after nextInt() problem.
 
Marshal
Posts: 79828
388
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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: 10920
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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: 10920
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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: 7125
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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: 7125
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Anyone interested in how I dealt with this problem can look at:

https://github.com/ksnortum/Inputer
 
Sheriff
Posts: 8908
638
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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: 10920
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Updated with private constructor.
 
Campbell Ritchie
Marshal
Posts: 79828
388
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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.
     
    Sheriff
    Posts: 17665
    300
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • 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: 79828
    388
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • 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: 7125
    184
    Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • 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.
     
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    This topic continues to appear so I'm posting my current version which has a number of "prompt......()" methods in it.

    As it has been pointed out, wrapper methods like nextInt() are provided without modification to the original Scanner#nextInt() method. This means that the Keyboard.nextInt() method does NOT address the issue of a pending new-line being left in the queue. I left it this way on purpose because the user should really be making use of one of the "prompt....()" methods instead, or add their own if mine is insufficient. Also note that the prompt....() methods call KBD.nextLine() as opposed to KBD.nextInt() for example. This elevates the need to deal with the pending new-line problem and should work properly because this Scanner instance is only for keyboard input where it is not expected that more than one value would be input at a time. It does not preclude writing your own method to handle the inputting of multiple values, I just felt that as a standard wrapper class that was a bit out of scope.

    Also, I believe that Campbell Ritchie has posted code for a similar utility. I just searched for it just as a point of comparison but was unable to find it (it's there, just couldn't find it at the moment). If someone knows the link to his post please add it to this thread.
     
    Bartender
    Posts: 2911
    150
    Google Web Toolkit Eclipse IDE Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    You've made a nice Decorator for Scanner. My only nitpick is can we call it something other than "Keyboard" ?
    How about "KeyboardScanner" or Knute's "Inputer"
     
    salvin francis
    Bartender
    Posts: 2911
    150
    Google Web Toolkit Eclipse IDE Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    My suggestion for boolean :
     
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Why "Optional" when there's no chance of returning Optional.empty()?
     
    salvin francis
    Bartender
    Posts: 2911
    150
    Google Web Toolkit Eclipse IDE Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Good Catch
     
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Also, the point of my prompt() methods is to have the loop internally to re-prompt if necessary rather than to throw an exception.
     
    Liutauras Vilda
    Sheriff
    Posts: 8908
    638
    Mac OS X VI Editor BSD Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Let me put some of my thoughts for the method I chose randomly:

    1. Looking to method's name first thing which comes to mind is: hm.. "ok, let me have a look again, what does it do/say?".
       1.1 promptBoolean, is it wrapper class going to be returned Boolean or primitive boolean? (as subsequent methods indeed return wrapper). I'd avoid Boolean mentioning at all if name cannot suggest clearly what it is going to be returned. In this case it misleads even due to camel case convention. IDE's are clever enough to show return type of method, so to clutter method names with types information makes it harder to read (personally to myself). When methods say getPerson() - in my head I interpret that: "give me person's blueprint/description/entity, but not its class it is implemented in".
       1.2 YN postfix. I'd think it is poor choice. Suggests YN but accepts answers true; false; yes; no; as valid. Again, method name suggests upper cases, while hint upon incorrect input suggests lower cases.

    And most of the method names are cluttered in my opinion with the information what the method's signature along with return type should and do provide already.
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Carey Brown wrote:Why "Optional" when there's no chance of returning Optional.empty()?

    Agree; the only methods of a Scanner that can retun null are the two methods whose names start “find”, Those seek a match for a regex and an Optional<String> might be an appropriate return type of those methods are used. All other methods throw an exception if they don't find the input to be the correct type.
    I am not happy with while (true) ... and exception handling. Rob Spoor taught me the loop I use, ages ago; it completely obviates any risk of an input mismatch exception. The escapes \u201c and \u201d are posh quotes: ””You can do the same sort of thing for yes/no:-Note:
  • 1: No need for next() call inside the loop.
  • 2: equalsIgnoreCase() is called twice per loop, but compared to speed of keyboard input, that is probably nothing to worry about.
  • 3: I have missed out the overloading for brevity's sake.
  • 4: I presume everybody is familiar with the strange syntax in line 6.
  •  
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Liutauras Vilda wrote:Let me put some of my thoughts for the method I chose randomly:

    1. Looking to method's name first thing which comes to mind is: hm.. "ok, let me have a look again, what does it do/say?".
       1.1 promptBoolean, is it wrapper class going to be returned Boolean or primitive boolean? (as subsequent methods indeed return wrapper). I'd avoid Boolean mentioning at all if name cannot suggest clearly what it is going to be returned. In this case it misleads even due to camel case convention. IDE's are clever enough to show return type of method, so to clutter method names with types information makes it harder to read (personally to myself). When methods say getPerson() - in my head I interpret that: "give me person's blueprint/description/entity, but not its class it is implemented in".
       1.2 YN postfix. I'd think it is poor choice. Suggests YN but accepts answers true; false; yes; no; as valid. Again, method name suggests upper cases, while hint upon incorrect input suggests lower cases.

    And most of the method names are cluttered in my opinion with the information what the method's signature along with return type should and do provide already.


  • Does it return Boolean or primitive boolean? I was following the naming convention suggested by various Scanner methods, such as nextBoolean() which happens to return a primitive boolean. The acceptance of "yes" or "no" as well as "y" or  "n" follows a long history of reading other people's code for similar methods. I'll admit that also accepting "true" and "false" was a stretch, and I probably should have left it off.
  • Should the return type be part of the name? You happen to pick on the YN methods, where "Boolean" in the method name was overkill. I was trying to be consistent with the naming suggested by the Scanner class. Other methods require including the type because otherwise the method name/signature would be the same, e.g. promptDouble(...). In the case of YN I could have left off the return type.
  • YN posfix is a poor choice? Camel case is sometimes limiting. Would you prefer "promptyn()", or "promptyyesnno?
  • The hint is also a problem because it shows the expected response in lower case? Should it hint of 'Y' or 'N'? That would suggest that the user add additional keystrokes which is not the case. I can't control the text of the prompt that is passed in, so it might say "Y/N" or "y/n", I wouldn't know. I wouldn't want to require the caller to also pass in an error message as well, but that would be possible. I think this hint suffices.
  •  
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:

    Carey Brown wrote:Why "Optional" when there's no chance of returning Optional.empty()?

    Agree; the only methods of a Scanner that can retun null are the two methods whose names start “find”, Those seek a match for a regex and an Optional<String> might be an appropriate return type of those methods are used. All other methods throw an exception if they don't find the input to be the correct type.
    I am not happy with while (true) ... and exception handling. Rob Spoor taught me the loop I use, ages ago; it completely obviates any risk of an input mismatch exception. The escapes \u201c and \u201d are posh quotes: ””You can do the same sort of thing for yes/no:-Note:
  • 1: No need for next() call inside the loop.
  • 2: equalsIgnoreCase() is called twice per loop, but compared to speed of keyboard input, that is probably nothing to worry about.
  • 3: I have missed out the overloading for brevity's sake.
  • 4: I presume everybody is familiar with the strange syntax in line 6.

  • I specifically prefix my method names with "prompt". I explicitly expect a new-line to follow each input by using nextLine().  I have found this to be a decent approach for keyboard input. This eliminates the need for a nextLine() call to clear out any pending new-lines in the input stream. I have also chosen to leave the "next...()" wrappers intact, warts and all. I suggest using the "prompt...()" methods instead if you want proper handling of those issues.  I suppose there might be a case where throwing an exception might be necessary but the goal is to have the prompt...() methods handle input issues gracefully without bothering the caller.
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    In my code, the only place you would get an exception is if you called KeyboardInputs.nextInt("Please enter score: ", 100, 0); and you are working in the range 100…0 
    I shall have to have a closer looks the your prompt method later.
     
    Liutauras Vilda
    Sheriff
    Posts: 8908
    638
    Mac OS X VI Editor BSD Java
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Carey Brown wrote:Does it return Boolean or primitive boolean? I was following the naming convention suggested by various Scanner methods, such as nextBoolean() which happens to return a primitive boolean. The acceptance of "yes" or "no" as well as "y" or  "n" follows a long history of reading other people's code for similar methods. I'll admit that also accepting "true" and "false" was a stretch, and I probably should have left it off.
    Should the return type be part of the name? You happen to pick on the YN methods, where "Boolean" in the method name was overkill. I was trying to be consistent with the naming suggested by the Scanner class. Other methods require including the type because otherwise the method name/signature would be the same, e.g. promptDouble(...). In the case of YN I could have left off the return type.
    YN posfix is a poor choice? Camel case is sometimes limiting. Would you prefer "promptyn()", or "promptyyesnno?
    The hint is also a problem because it shows the expected response in lower case? Should it hint of 'Y' or 'N'? That would suggest that the user add additional keystrokes which is not the case. I can't control the text of the prompt that is passed in, so it might say "Y/N" or "y/n", I wouldn't know. I wouldn't want to require the caller to also pass in an error message as well, but that would be possible. I think this hint suffices.


    Now that I read again, I think I've sounded negative, I'm sorry if that was the case, but certainly didn't want to. At the same time, I wanted to be honest, and mention, that I found some of API methods to be less than intuitive, but let me try to clarify some aspects which confused me most I guess as potential user (note: now that I looked to them for some time became more clear ).

    In many cases when I saw "prompt" mentioned in a method name, usually method had the text to prompt, i.e.: prompt("What is your name?");. Now that's changed, you introduced return type to method as well as accepted set of values, and that probably confuses me mainly.

    You know that class Objects.requireNonNull().

    Maybe method names would have read better as:
    instead

    That way to me seems separated what is returned from what is required as an input.

    However, still prompt for me personally clutters method names. But maybe because I don't understand 100% its meaning. From old Windows systems prompt I used to interpret as popup with some text. So promptBoolean kind of doesn't make sense then to me.

    What if? (my preferred version to be honest now that I spell it)

    Maybe...:

    So once again, I guess just intuitiveness of method names are stoppers for me as of now, and not the implementation of them.

    Would similarly think about other method names, just to refine them to add clarity.


    Carey Brown wrote:I'll admit that also accepting "true" and "false" was a stretch, and I probably should have left it off.


    I too think that would make it simpler, clearer.

    So apologies once again if I managed to sound very negative initially.
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Yesterday, I wrote:. . . I shall have to have a closer looks the your prompt method later.

    Nothing new to say about it.
     
    Ranch Hand
    Posts: 603
    Eclipse IDE Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:

    Yesterday, I wrote:. . . I shall have to have a closer looks the your prompt method later.

    Nothing new to say about it.



    Which is the updated wrapper class for Scanner(System.in)
    Please share the thread link

    Regards,
    Deepak Lal
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Deepak Lal wrote:. . . Please share the thread link

    Regards,
    Deepak Lal

    It's this thread. Look at the top of the thread.

    My utility class is different, and I haven't posted the whole of it anywhere.
     
    Saloon Keeper
    Posts: 28244
    198
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Interesting note: On the Prime Minicomputer OS, there was a function you could call named "ayenay()". It would accept a word and return true if the word had the value of "yes", "true" or "aye" (someone had humor there, I think). It actually would take the full text or the first letter(s) thereof.
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Grace Hopper was an Admiral. She would obviously require nautical terms be used; sailors never say yes but, “Aye‑aye, Sir.” That means all yes‑no programs should accept “aye”.
     
    Tim Holloway
    Saloon Keeper
    Posts: 28244
    198
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Aye, but I'm not sure the Navy was a big Prime Computer customer. And ayenay wasn't COBOL, it was Fortran.
     
    Campbell Ritchie
    Marshal
    Posts: 79828
    388
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    If it was Fortran, that was probably before the word yes came into common use in English
     
    Carey Brown
    Saloon Keeper
    Posts: 10920
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Added promptDoubleRange().

     
    Men call me Jim. Women look past me to this tiny ad:
    Gift giving made easy with the permaculture playing cards
    https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
    reply
      Bookmark Topic Watch Topic
    • New Topic