10

Java is object oriented, but, why do we need to create an object from the Scanner Class to get input? Couldn't next() methods, for example, just be Static?

C looks to me pretty simpler as you just use scanf(), gets() or fgets(). I'm sure there's a reason for Java developers for creating the Scanner class, but how is it better than just having a normal function to do the work?

I've found this link that may seem asking the same question, but answers are just about

"you need to create an object because is not static"...

My guess is: since Java is Object Oriented, they decided to put all input methods in a class. They didn't do static methods so you can have all kind of different sources (keyboard Input, file Input...) in different objects ?

I would appreciate if someone can edit the question to make it sound more clear!

34

The answer is "because a scanner has state."

Looking at the code for java.util.Scanner, you will see a number of private fields such as a buffer and its associated information, a Matcher, a Pattern, an input source, information about if the source is closed or not, the type of the last thing matched, information about if the last thing was a valid match or not, the radix used for numbers, the locale (information about if you are using . or , as a thousands separator), and its own LRU cache for recently used patterns, the information about the last exception that was encountered, some information about parsing numbers, some information about parsing booleans, quite a bit more information about parsing integers... and I think thats about it.

As you can see, thats a fairly large block of text there. That is the state of the Scanner. In order to make the Scanner into a static class, that state would need to be stored somewhere else. The C way of doing it really doesn't have that much state with it. You've got a fscanf. The FILE maintains some state about the position it is at (but that needs to be passed in for each invocation of fscanf). If there was an error, you have to process it (and then you start writing code that looks like this) - and that doesn't tell you information like "I was expecting an Integer, but found a String."

When one looks at the theoretically static Scanner - all of the state is maintained outside of the class, it isn't encapsulated within the class. Other bits of code could tinker with those variables. When other code can tinker with the state of the class, it becomes very difficult to reason about what the class will do in any given situation.

You could, maybe, write something like ScannerState { Locale loc; ... } and have code that results in:

ScannerState state = new ScannerState(a whole lot of arguments);
int foo = Scanner.nextInt(state);

But then, this is much more cumbersome than having the state encapsulated within a Scanner object in the first place (and not needing to pass in the state).

Lastly, the Scanner implements the interface of Iterator<String> which means that one can use it in code such as:

Scanner in = new Scanner(someFile);
whie(in.hasNext()) { ... }

Without being able to get an instance of the Scanner class, this type of structure becomes more cumbersome within an object oriented language.

  • 1
    Everything you wrote is absolutely true, though InputStream has state as well, not just Scanner. If the input is coming from the console, like in C, you don't need to pass any parameters to start taking input. I suppose it was done this way to be consistent with how other streams are done which do require state. – Neil Aug 31 '15 at 6:23
  • @Neil InputStream equates to the FILE* (position state) in C. – ratchet freak Aug 31 '15 at 9:16
  • 1
    Scanner implements Iterator - not Iterable. It's impossible to use Scanner in enhanced-for loop. – turbanoff Aug 31 '15 at 9:22
  • @ratchetfreak Precisely. That is what "state" FileInputStreams must have, but it doesn't apply for input from console since it is already technically open. – Neil Aug 31 '15 at 10:26
  • 1
    @turbanoff Thank you for calling me out on that. I've corrected it. – user40980 Aug 31 '15 at 13:07
7

short answer: you don't. You can get user input without using a Scanner instance.
For example: https://docs.oracle.com/javase/tutorial/essential/io/cl.html or
http://alvinalexander.com/blog/post/java/java-source-code-read-command-line-input

  • String orgName = (new BufferedReader(new InputStreamReader(System.in))).readLine(); That's horribly convoluted compared to using a Scanner and also creates new instances of not one but two objects just to discard them right away. – Philipp Aug 31 '15 at 11:36
  • 2
    @Philipp, 1) It's cumbersome, but it's certainly an alternative, and 2) if you're discarding the instances right away you're doing something wrong (or you truly only need to read one line from console). – Arturo Torres Sánchez Aug 31 '15 at 12:23
  • You don't need Scanner to read input. You also don't need an InputStreamReader and you don't need a BufferedReader. You can work with the "raw" stream at System.in, just like in C. Scanner is simply a very comfortable way to consume that stream. – Traubenfuchs Jun 2 '16 at 9:03

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.