![]() |
| CS Home » My Home Page » Teaching » class Input |
class Input
|
|
Note an interactive program using Input must be run from the command line (an xterm window, or a MS Windows Command Prompt window, or a Mac OS X terminal window, or a programming environment that supports an equivalent kind of window). Simply open the appropriate window, change to the correct directory and use the java command (e.g., java MyInteractiveProgram). You can still edit and compile the program using JEdit or BlueJ. |
A program that needs to do input first has to create a Input object using the Input class. Do this by having a line in your program that looks like this:
Input input = new Input() ;
This line must appear before you do any input and will give you a variable called input that references an Input object. The examples use the variable name input but you can use any valid and relevant name. Once you have an Input object you call its methods to input values. For example, to input an integer you would use:
int x = in.nextInt() ;
When this statement is executed, the program will wait for you to type in some input. The input must be finished by pressing the <return> key, otherwise nothing more will happen! Once the input has been read an attempt will be made to recognise the characters that were typed in as an integer of type int. If successful the int value will be returned and the variable x initialised. If not, then the programs terminates with the message "Input did not represent an int value".
To let someone using your program know that input is expected, it is a good idea to print a message asking for the input. For example:
System.out.print("Type a floating point number: ") ;
double d = in.nextDouble() ;
Note the use of print, rather than println, so that the input follows the message on the same line.
The following test program shows the use of some of the input methods provided by the class. To run this program, save the source code to a file called InputTest.java and compile and run it, having first made sure that a copy of Input.class is in the same directory.
public class InputTest
{
public void inputNumbers()
{
Input input = new Input();
System.out.print("Type an integer: ");
int n = input.nextInt();
System.out.println("Integer was: " + n);
System.out.print("Type a long: ");
long l = input.nextLong();
System.out.println("Long was: " + l);
System.out.print("Type a double: ");
double d = input.nextDouble();
System.out.println("Double was: " + d);
System.out.print("Type a float: ");
float f = input.nextFloat();
System.out.println("float was: " + f);
// Note this extra input needed to remove the newline
// left after reading the float.
input.nextLine();
System.out.print("Type a word: ");
String s = input.nextLine();
System.out.println("Word was: " + s);
System.out.print("Type a single character: ");
char c = input.nextChar();
System.out.println("Character was: " + c);
}
public static void main(String[] args)
{
new InputTest().inputNumbers();
}
}
Methods named next<type> (for example, nextInt), attempt to read a value of the specified type. Any whitespace characters (space, tab, newline) before the actual value characters are ignored.
For each next<type> method there is also a hasNext<type> method, for example hasNextInt. These methods return true if the next non-whitespace characters typed in represent a value of the specified type, false otherwise. If there is no input available, calling a hasNext method will wait for the user to type something in and press <return>.
Input from the keyboard is buffered in an input buffer managed by other classes in the Java class libraries. This means that the characters typed when you are prompted to enter a value are collected up and temporarily stored until the <return> key is pressed. Your program is kept waiting while you are typing, so your program is not actually doing anything. Only after the <return> key is pressed does your program carry on executing. While your program is waiting we say it is suspended or blocked.
As a result of the buffering your program receives a whole line of characters at a time, not single characters one after another as they are typed. The line of characters includes a newline character at the end newline is the character generated by pressing <return>. When you input a value using a next method like nextInt, an attempt is made convert the characters in the buffer to a value of the right type, in the order the characters appear. For example, if the buffer contains:
"123\n"
(where \n is a newline) then the characters '1', '2' and '3' are read and converted to 123. Whitespace characters (spaces, tabs, newlines) before the 123 are skipped, so:
" 123\n" or "\n123\n"
also results in 123 being input. If there are non-digit characters that are not whitespace before the input value, the input will fail:
"ab 123\n"
The characters "ab" cannot be converted to an int (in base 10), so input fails and the program terminates, regardless of the characters that appear later in the buffer.
If the input buffer contains:
"123 456\n"
then getting an int value using nextInt will return 123, leaving the rest of the characters in the input buffer. Inputting another int will read 456 without the program waiting for the user to type more input as the buffer already contains an integer.
If a program prompts the user to type in two integers, one after another, at the first prompt the user can enter:
"123\n"
Then at the second prompt:
"456\n"
When the first int is read the \n is left in the input buffer. When the second int is read, the \n in the input buffer is skipped over as it is whitespace. The program will then wait for the input buffer to be filled again by the user typing the next integer. This highlights that the next input is always read starting with the current contents of the buffer. The program will only wait for the user to type more input when the buffer needs to be filled. If a program does not wait for input when you expected it to, then you need to take into account this behaviour when working out what is happening.
Using the nextLine method will return a String containing the entire contents of the buffer (i.e., an entire line of text). The newline character is read and discarded, leaving the buffer empty. If nextLine is called when the buffer is already empty, the program will wait until something is typed in.
The nextChar method can be used to read a single character from the buffer. Reading a newline character, returns the newline and it is not discarded as when using nextLine.
The class Input code listing follows (or click here and use Save Link to save file directly). The class uses a number of Java features that are not covered in COMP1007, along with several library classes. At this stage an understanding of how the class works is not needed but it is well worth the challenge of looking through it and trying to work out what all the code does. Use the text book to help. Also, note the way the class has been commented. It has actually been fully commented using documentation comments, which can be automatically processed to produce online documentation in the form of web pages. Documentation comments can include HTML tags to control the formatting, so the appearance of tags like <code> and <p> is not an error.
import java.io.Closeable; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.util.InputMismatchException; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Scanner; /** * An iterator class to input specific data types from an input stream without throwing any * exceptions. If there are any errors during use of the iterator then a message is output to * the standard output and the program terminates. * * This is just a simple wrapper aroundScannerthat implements a subset of the *Scannerpublic interface. * * This class is useful for people new to Java since it allows them to write programs using * input without having to fully understand the read / parse / handle exceptions model of the * standard Java classes and in particularScanner. So once exceptions and object * chaining are covered this class ought not to be used, it is definitely just an "early * stepping stone" utility class for initial learning. * * @author Russel Winder * @version 2004-12-16 */ public class Input implements Closeable, Iterator{ /** * A reference to the associated Scannerthat supplies all the actual input * functionality. * * This is protected and not final rather than private and final (as we might have * expected it to be) so thatFileInputcan access the variable. This is * necessary becauseFileInputneeds to capture all exceptions that can happen * during construction, which means that thesuperconstructor call cannot be * used. This appears to be something of a misfeature of Java. */ protected Scanner scanner; /** * The default constructor of anInputthat assumesSystem.inis to * be theInputStreamused. */ public Input() { this(System.in); } /** * Constructor of anInputobject given anInputStreamobject. */ public Input(final InputStream in) { scanner = new Scanner(in); } /** * A finalizer to ensure all files are closed if anInputobject is garbage * collected. */ public void finalize() { close(); } /** * Close the file when finished with it. */ public void close() { scanner.close(); } /** * @returntrueif there is more input,falseotherwise. */ public boolean hasNext() { boolean returnValue = false; try { returnValue = scanner.hasNext(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the next token (sequence of characters terminated by a whitespace) in the input * stream. */ public String next() { String returnValue = null; try { returnValue = scanner.next(); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * This operation is required in order to conform toIterator<String>but is * not supported. Normally anUnsupportedOperationExceptionwould be thrown to * indicate this situation but the whole point is not to throw exceptions so this is simply a * "do nothing" method. */ public void remove() { } /** * NB This method currently has a mis-feature in that it returns false incorrectly when there * is a single end-of-line left in the file. * * @returntrueif there is acharto input,false* otherwise. */ public boolean hasNextChar() { // Why doesn't this work, it used to. //boolean returnValue = false ; //try { returnValue = scanner.hasNext ( "(?s)." ) ; } //catch ( IllegalStateException e ) { illegalStateExceptionHandler ( ) ; } //return returnValue ; return hasNext(); } /** * @return the nextcharin the input stream. */ public char nextChar() { char returnValue = '\0'; try { returnValue = scanner.findWithinHorizon("(?s).", 1).charAt(0); } catch (IllegalArgumentException iae) { // This cannot happen as it is clear in the statement that the horizon is 1 which is > 0 and // this exception only happens for negative horizons. System.exit(1); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is anintto input,false* otherwise. */ public boolean hasNextInt() { boolean returnValue = false; try { returnValue = scanner.hasNextInt(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextintin the input stream assumed to be in the default radix * which is 10. */ public int nextInt() { int returnValue = 0; try { returnValue = scanner.nextInt(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("int"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @param radix the radix of the input. * @return the nextintin the input stream using the radix *radix. */ public int nextInt(final int radix) { int returnValue = 0; try { returnValue = scanner.nextInt(radix); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("int"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is alongto input,false* otherwise. */ public boolean hasNextLong() { boolean returnValue = false; try { returnValue = scanner.hasNextLong(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextlongin the input stream assumed to be in the default radix * which is 10. */ public long nextLong() { long returnValue = 0; try { returnValue = scanner.nextLong(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("long"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @param radix the radix of the input sequence. * @return the nextlongin the input stream using the radix *radix. */ public long nextLong(final int radix) { long returnValue = 0; try { returnValue = scanner.nextLong(radix); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("long"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is aBigIntegerto input,false* otherwise. */ public boolean hasNextBigInteger() { boolean returnValue = false; try { returnValue = scanner.hasNextBigInteger(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextBigIntegerin the input stream assumed to be in the default * radix which is 10. */ public BigInteger nextBigInteger() { BigInteger returnValue = new BigInteger("0"); try { returnValue = scanner.nextBigInteger(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("BigInteger"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @param radix the radix of the input sequence. * @return the nextBigIntegerin the input stream using the radix *radixtrueif there is afloatto input,false* otherwise. */ public boolean hasNextFloat() { boolean returnValue = false; try { returnValue = scanner.hasNextFloat(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextfloatin the input stream. */ public float nextFloat() { float returnValue = 0; try { returnValue = scanner.nextFloat(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("float"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is adoubleto input,false* otherwise. */ public boolean hasNextDouble() { boolean returnValue = false; try { returnValue = scanner.hasNextDouble(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextdoublein the input stream. */ public double nextDouble() { double returnValue = 0; try { returnValue = scanner.nextDouble(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("double"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is aBigDecimalto input, *falseotherwise. */ public boolean hasNextBigDecimal() { boolean returnValue = false; try { returnValue = scanner.hasNextBigDecimal(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return the nextBigDecimalin the input stream. */ public BigDecimal nextBigDecimal() { BigDecimal returnValue = new BigDecimal("0"); try { returnValue = scanner.nextBigDecimal(); } catch (InputMismatchException ime) { inputMismatchExceptionHandler("BigDecimal"); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * @returntrueif there is more input including an end of line marker, *falseotherwise. */ public boolean hasNextLine() { boolean returnValue = false; try { returnValue = scanner.hasNextLine(); } catch (IllegalStateException e) { illegalStateExceptionHandler(); } return returnValue; } /** * @return all the characters in the input stream up to and including the next end of line * marker in the input stream. */ public String nextLine() { String returnValue = null; try { returnValue = scanner.nextLine(); } catch (NoSuchElementException nsee) { noSuchElementHandler(); } catch (IllegalStateException ise) { illegalStateExceptionHandler(); } return returnValue; } /** * The method to handle anIllegalStateException. */ private void illegalStateExceptionHandler() { System.err.println("Input has been closed."); System.exit(1); } /** * The method to handle anInputMismatchException. */ private void inputMismatchExceptionHandler(final String type) { System.err.println("Input did not represent " + (type.equals("int") ? "an" : "a") + " " + type + " value."); System.exit(1); } /** * The method to handle anNoSuchElementException. */ private void noSuchElementHandler() { System.err.println("No input to be read."); System.exit(1); } }
Last updated:
September 12, 2008 |
Computer Science Department - University College London - Gower Street - London - WC1E 6BT -
+44 (0)20 7679 7214 - Copyright ©1999-2011 UCL