One of the first things you'll need to do when you're learning Java
is to write lots of programs that take input from a user and store it in your program.
Unfortunately, many beginners just start banging away with Scanner
(more often than not, in main()
), only to discover when they're about halfway through - and after they've written a LOT of code - just what a damn fiddly process user input is.
This page is designed to help you to write this stuff properly
, and it assumes that your program is console-based (ie, you're running it from the command line), and it doesn't
use Swing or web pages for display - or at least not until after
you've got your input.
It takes you through the process step by step, so it's fairly long. Don't worry; the final result is quite straightforward. It's also in two parts: in the second
, we'll go into the business of writing your own utility class to do this, so you don't have to keep repeating the same code.
User input is tough
. It's finicky, it's fiddly, and you need to deal with all sorts of things that can possibly go wrong - not the least of which is that your user is a complete idiot
, and doesn't follow instructions.
The general pattern
for each value
that a user needs to enter goes something like this:
Unfortunately, most books/classes simply show you the basics of Java's Scanner
class and leave you to get on with it; and it's NOT simple.
First: You're dealing with a complex process, so you need to design it
a simple class - although it's a lot simpler than many of the alternatives - and it has several idiosyncrasies and "gotchas" that you need to know about in order to use it properly.
My strategy will be simple: I'm going to teach you how to avoid
them, so that you can get on with the business of getting input from your user
KICKOFF - Getting an Integer:
So, you need a number from your user.
The first thing you need to understand is that the keyboard is a character
device, so, whenever you press a key, it returns a character, not a number - even if that character is '2'.
Characters are NOT the same thing as numbers, so in order to get an integer
(ie, an int
or an Integer
), you need to convert
the character - or, more likely, the string
of characters - entered by the user.
Let's suppose, just for a moment, that you've discovered that Scanner.nextInt()
can take input from the keyboard and return you an integer, so you write:
Now normally, this will work just fine; but today but your idiot user decides to type in "X" instead of a proper number. What happens?
Answer: Your program fails with an Exception. Specifically: an InputMismatchException
Do you really want that to happen? If you're happy with that behaviour, then your job is done and you can skip the rest of this tutorial. Seriously
write code you don't have to.
But might it not be better to include that step 4
logic you saw above? - ie, tell them they're an idiot and keep prompting for input until they get it right.
is where the problems start (and basically what this tutorial is all about).
In order to do that, you need to know if the method you just called threw an Exception or not; and for that you need a try...catch
So you write:
What do you do? You can't use the value of your int
field, because any value you choose to indicate an error might be a perfectly valid number that they actually typed in correctly. Furthermore, we haven't yet included any looping mechanism that forces them to enter it again until they get it right.
So, lets do that:
will work. It's crude, but it will work because the loop will just keep cycling until they enter something that doesn't
cause an InputMismatchException; so by the time you get to "next statement" you'll know
that they entered a valid number.
But good grief
, it's a lot of code - and it's ugly too. And you have to do it (or something like it) for every single value you ask your user to enter
Suppose your program needs to collect TEN numbers from the user; what do you do then? Repeat all that code 10 times? BAD IDEA.
Put it in a loop? Possibly; but what if you need different prompts for each number? What if some of them need to be validated further? For example: what if one
of them is a Month, so you need to make sure your idiot user enters a value between 1 and 12. You could certainly add logic to do it, but you couldn't
put it in the loop - and besides, it's just more code
And so far, we've only dealt with integers
. What about decimal numbers (eg, 1.25), or booleans (eg, YES/NO), or zip codes? There are a whole bunch of things we might need to ask for, and even more ways to validate it.
At this point, I usually advise programmers to StopCoding
We need some way to rationalise
this process, rather than just adding scads and scads of code.
So, what's wrong?
: We're using Scanner's conversion methods, which are brittle because they lump the process of scanning and conversion together. They also have other idiosyncrasies, such as missing out newlines, which nobody warns you about until you run into them.
So my advice (and you won't find it in too many books): forget them
There is only one
method (other than close()
) that you need to know about when using a Scanner: nextLine()
This takes whatever characters a user enters until they hit the ENTER key, and returns them to you as a Java String
. No validation, and no errors other than ones that your program can't possibly do anything about.
So what you get is a String
you can worry about validation and/or conversion.
Furthermore, the method doesn't return until
the user presses the ENTER key, and
it consumes the newline character; so you know
that your Scanner is always in a state to accept another line of input.
CAVEAT: Not everybody will agree with the above advice. It's my opinion, based on several years of dealing with Scanner, and it follows a very old programming principle: Keep things simple
I should add that it hasn't steered me wrong ... yet
We need to normalise our input process by putting in a method
. In fact, probably more than one.
: We need to analyse the sorts of thing we might need to do when a user enters a value, so that we don't need to write a new method for each new input.
Integer input, revisited:
So, how do we turn a String into an int
(or indeed - possibly better - an Integer
A quick look at the Integer
class docs will tell you how:
For an int, you use: parseInt(String).For an Integer, you use: valueOf(String).
accomplishes pretty much exactly
the same thing as:
The only thing I would suggest is that you add a call to String.trim()
to make sure any extra spaces your idiot user might have inadvertently typed in at the start or end of the line are removed. So you get:
and putting that in our previous loop we get:
Also: note the different Exception: parseInt()
, not InputMismatchException
However, our loop is now even bigger
, so let's have a look at that second
point we mentioned...
Putting it in methods:
OK, now we now have a loop we can use, but it's still awfully
cumbersome. 12 lines of code to deal with one
value? How do we rationalise it?
First: we can put all that code, which we would otherwise have to repeat for each value, into a method (actually, methods, as you'll see below).Second: we can use objects instead of primitives.Third: we can split up the input from the looping.
Why objects? Because they have one great property that we can use to our advantage: they can have a value of null
; and we can use that
to know when there's been a error.
So: lets have a look at the input part of our loop (just
the input for now), and see if we can't break it up a bit and put it into methods.
: We need to actually get some input from a user and trim it; and when we do, we will almost certainly want to display a prompt message first. So let's do it:
Simple, eh? The method displays the prompt message we pass to it and returns the String they enter, trimmed of any whitespace at the start and end.
: We need to convert that String to a number - which is where we may get the Exception. For the moment, our remedy is to simply return null
if there's a problem:
which can be shortened to:
Note that we've made this method private
because it's really only for our
use; and also note the use of valueOf()
because we're returning an Integer
we're returning an Integer
, which is an object
, we can return null
if there's a problem. We can't
do that if we return an int
: This is one of the very
few cases where I advise returning null
. In general, you should avoid them like the plague, but in this particular case it provides a very useful piece of information ("something went wrong with the conversion") that we can't get easily any other way.
our loop becomes slightly different:
Much smaller - however, it's still
a lot of code for our main()
method, so why not put it
in a method too?
Let's take a first cut at it. And while we're at it, let's tone down those messages a bit - it's not a great idea to be too
rude to your users, no matter how tempting it might be
which you would then call with something like:
in your main()
method. And just in case you're worried: an Integer
will be "unboxed" to an int
, so there's absolutely nothing wrong with the assignment.
Just FYI, we can remove the duplicate integerOrNull()
call by making it part of the loop test, viz:
however, if you do so, you MUST remember to put the assignment inside brackets, because its operator ('=
') has a lower precedence
than the equality operator ('==
I have to admit to a slight preference for the second style, so I will be using it for the rest of this tutorial; but be aware that some senior programmers really don't
like "compound" expressions like this. And if you prefer the first, which is arguably a bit clearer, feel free to use it instead.
Did you also notice that we're now supplying a 'suffix
'? The "Please enter "
is redundant, because we'll probably want to prefix pretty much every request for input with it (or something similar), so we might as well just put it in the method.
And that's another
thing that makes user input so verbose: all those darn prompt and error messages you have to write. And I hate to say, but there's not much you can do about it.
Just to make sure you follow, let's go through the process in detail:
, which calls input()
, which first displays the prompt:
and then waits for the user to type in some characters and press the ENTER key
(very important); returning whatever they typed in to integerOrNull()
as a String
If they entered something invalid, then valueOf()
will throw an Exception, causing integerOrNull()
to return null
, which in turn causes getInteger()
to enter the while
loop. The first thing it does there is to display the error message:
and then call integerOrNull()
again, which calls input()
However, as soon as the user gets it right
will return something other
, which causes getInteger()
to break out of the loop (or never enter it, if they get it right first time) and return the converted value.
Now that probably sounds like an awful lot of stuff, but essentially, it's exactly
the same process we were doing before in our loop; we've just broken it up into discrete tasks. And, most important of all, we've removed it from main()
Make sure you follow it before you continue. You may also find it helpful to look at the class listing
, where everything is shown together.
Now it may seem as though we've just added a lot more code; but just look at what happens when your idiot user needs to enter 10 values:
10 lines instead of 130
This is how you design programs: By reusing code.
Note that the methods must
because we're calling them from main()
, which is itself static
; and static methods should almost invariably be final
There's also no real reason to make them anything else, because they're self-contained - ie, they don't rely on any instance
values to do their jobs.
We can also use this pattern for any other type of number, viz:
And that probably covers the major types of number you'll need for now.
It's probably also worth adding that the problem of conversion Exceptions is peculiar to numbers
. For other input, we usually don't have to worry about it.
But hold on hoss, we're not done yet. Not by a long
So...what's wrong NOW?
We now have a method that can return a number input by a user, but what if we need our user to enter a Month (ie, a number between 1 and 12)?
Sure, we could write something like this:
But then we'd need a different method for a month number, or a week number, or somebody's age, or salary, or test score... the possibilities are almost endless.
Isn't there some way we can make this more generic?
Well as it turns out, there is; but it takes a bit of thought
. And this is something you should get into the habit of doing. ALWAYS. Think before you start coding
The fact is that almost all requests for numbers fall into two basic categories:
Any old number - which we've already seen.A number within a range - as with our month example.
There is a third - a number from a specific set of "valid numbers" - but that's beyond the scope of this tutorial.
So lets write a more generic method that takes a range:
Note that we didn't use a "compound" expression as we did above
, because the loop test
is itself a compound expression, which would make the whole thing very cumbersome. This is the point at which clarity should win out over brevity.
, to get a month, we can get rid of our getMonth()
method altogether and just call:
and for an age:
and a salary:
And just in case you didn't work it out, the prompt for that last call will be:
see if you can work out why.
It's still quite a lot of code, but nowhere near as much as we'd have to write if we dealt with each value individually. And it's just a basic fact of life:
User input is fiddly
Do you also follow the process? We've built up code slowly, as we find a need, adjusting things along the way if we have to; and now, with four methods, we can deal with pretty much any integer input we're ever likely to want.
Also: notice that for each new level of validation, we need to write another loop
; just another reason why user input is so darn complex.
And, if you fancy a little exercise after all this reading:
See if you can use what you now know (including any of the methods you've already seen) to write a method that forces
the user to enter a prime
number between 1 and 100.
(Tip: You'll first need to know how to check if what they enter - assuming it's a valid number - is
prime or not)
I'm afraid we won't be able to check your efforts, but good luck if you decide to try.
Our class so far
Just to recap, our class will now probably look something like this (I've only the included the methods needed for integer input for illustration):
So far, we've only dealt with integers; what about the other types we mentioned earlier?
Well, the general pattern is the same: Use nextLine()
to get the input (or indeed, the input()
method we just wrote) and then validate it and, if necessary, convert
it to the type in question.
We already showed you what the methods for a Double would look like, and its "getInRange()
" method will be virtually identical to the one we wrote for integers, except that lowest
will be double
I don't propose to go through all numeric types (there are 8) - suffice to say they will all follow the same basic pattern and, to be honest, you probably don't need them all. But feel free to try a couple out for practise.
Instead, let's have a look at boolean
Note that there is no need for a separate conversion method because we're not calling anything that throws an Exception, so we don't need a try
Also notice the different nature of the prompt: Booleans are usually the result of a "yes/no"-style question.
So a call to this method in main()
might look something like:
and its prompt would then be:
Also notice that we can return the primitive, because we don't need a null
We can also combine
the methods we've just written to input other more complex items. For example:
See how easy it is? And no annoying loops this time, because our methods already take care of that.
There are simply too many types to go into exhaustively, but you can make life a lot easier for yourself if you follow some of the rules you've already seen:
Put each type of input in a separate method.Use Scanner.nextLine() to get your basic input; or, better still, an input() method, as shown above.If the input needs conversion that can throw an Exception (as in the case of numbers), put the conversion in a separate private method that returns null if there's any problem; then write a second method that loops while the returned value is null.Supply, at least, a Scanner and a prompt to each method.Let the looping method deal with the business of creating proper instructions and error messages for the user.(MOST important) Don't let the looping method return anything until you know that the user has entered valid data.
And before you go rushing off to copy down all the methods you've seen: they are only examples
, and there are many
ways to write them. It's the pattern
that's important, not the code. You may well have other things that you need to check for, so it's important that you've understood the process
, not memorized the code.
That said, I suggest you stick pretty close to what you've seen for the input()
methods - at least for now.
So, we've saved ourself a lot of code (although it might not seem like it at the moment); but do we really have to write all this stuff in every program we write
Well, considering that you were probably originally going to write it ALL out in longhand, in main()
, you should be darn pleased that you've got this far; but the simple answer is:
Of course not
But in order to do that, you need to think
Java is an Object-Oriented
language, and that means we get objects
to do our work for us. And since these methods are always going to be pretty much the same, we might as well put them in a single class designed specifically for the job
But that's the subject of UserInputPartDeux
For the moment, re-read this one and make sure you understand it. I also suggest that you try out some of the methods for yourself and test them.
Another thing you may well have to do is match an input string against a pattern. We have tons
of the darn things these days: bank codes, zip codes, Social Security numbers, telephone numbers, license plates... the list is endless.
I've left this section till last because, unfortunately, it involves a bit of knowledge about Regular Expressions
. Only a bit; but if you haven't run across them yet, you can skip it for now and go onto the second part
of this tutorial.
The basic procedure for patterns is the same as you've seen before - get the input, validate it, and keep telling the user they're an moron until they get it right - it's the 'validation' bit that's slightly different.
Let's take as an example, a British postal code. It has a very
specific format. Specifically, and in sequence
One or two letters.A digit (0-9).An optional letter OR digit.A space.A digit.Two letters.
Now you could
write a method that checks each character in turn to make sure it's correct, but it would be extraordinarily tedious and error-prone. Luckily, there's a wonderful method in the String class called matches()
, which does all this for you very easily. If you're not familiar with it, I suggest you read the link.
Suffice to say that the following statement will do a complete UK postal code validation for you:
I don't propose to explain how it works; just trust me: it does. If you want to find out more about regular expressions, click on the link above, or there are many good resources on the Net.
So, how do we use it? Let's have a look:
What? Did you think it was going to be mind-blowingly complex? We don't even need to pass a prompt because the method
defines what the message is going to be; and since we're returning a String, there are no fancy conversions that need to be done.
About the only thing to note is the toUpperCase()
call. UK postal podes mandate the use of CAPITAL letters, so just in case our idiot user forgot to press the Shift key, we might as well convert what he gave us to upper case ourselves and save a lot of hassle.
And now you've come to the end of this part of the tutorial. Make sure you understand it, and I also suggest that you try out some stuff for yourself before you go onto UserInputPartDeux