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!

asked Aug 30, 2015 at 23:56

2 Answers 2

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.

answered Aug 31, 2015 at 1:53
7
  • 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. Commented Aug 31, 2015 at 6:23
  • @Neil InputStream equates to the FILE* (position state) in C. Commented Aug 31, 2015 at 9:16
  • 1
    Scanner implements Iterator - not Iterable. It's impossible to use Scanner in enhanced-for loop. Commented Aug 31, 2015 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. Commented Aug 31, 2015 at 10:26
  • 1
    @turbanoff Thank you for calling me out on that. I've corrected it. Commented Aug 31, 2015 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

answered Aug 31, 2015 at 5:49
3
  • 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. Commented Aug 31, 2015 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). Commented Aug 31, 2015 at 12:23
  • 1
    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. Commented Jun 2, 2016 at 9:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.