Keyboard I/O

For the first nine years of its life, Java did not have any routines to do console input. The official spin from Sun was that you were supposed to use a GUI for interactive I/O. If you wanted to get input from the command line, you had to roll your own support using several classes. It was ugly, and it needlessly gave a bad impression of Java to generations of student programmers. Most teachers gave their students a class to do console I/O, and only taught the API support much later.

image

The JDK 1.5 release introduces a simple text scanner that can be used to read input. There is also a new method that provides a feature essentially the same as the printf() method used in C. We'll show examples of both of these over the next several pages.

System.in, out, and err

On all Unix operating systems and on Windows, three file descriptors are automatically opened by the shell and given to every process when it starts. File descriptor '0' is used for the standard input of the process. File descriptor '1' is used for the standard output of the process, and file descriptor '2' is used for the standard error of the process. The convention is so common because it is a part of the C language API.

These three standard connections are known as “standard in,” “standard out,” and “standard err” or error. Normally, the standard input gets input from the keyboard, while standard output and standard error write data to the terminal from which the process was started. Every Java program contains two predefined PrintStreams, known as “out” and “err.” They are kept in Java.lang.System, and represent the command line output and error output, respectively. There is also an input stream called System.in that is the command line input. This is also referred to as console I/O or terminal I/O.

You can redirect the standard error, in, or out streams to a file or another stream (such as a socket) using these static methods:

System.setErr(PrintStream err);
System.setIn(InputStream in);
System.setOut(PrintStream out);

Stdin and stdout are used for interactive I/O. Stderr is intended for error messages only. That way, if the output of a program is redirected somewhere, the error messages still appear on the console.

Keyboard input

Before JDK 1.5, reading from System.in was a real problem. System.in had to be wrapped in a BufferedReader, and exceptions had to be handled by the programmer. To get numeric input, you needed a readLine() followed by a method call such as Integer.parseInt() to convert the String. The Scanner class simplifies this to the point where it is nearly sane.

image

We still don't have a single class that reads values from stdin. What we have is a more general mechanism. The new class, java.util.Scanner, can wrap certain classes that are sources of characters (in particular, any class that implements java.lang.Readable). You can then pull chunks of characters called tokens from the scanner, and get them interpreted as ints, longs, floats, Strings, etc.

The class java.util.Scanner

The word “scanner” is a term used by compiler-writers. Scanning means “splitting an input stream into groups-of-characters-that-belong-together (tokens)”. By default, tokens are separated by whitespace (e.g. space, tab, newline). If you type at the keyboard “99 red balloons”, scanning will split this into three tokens “99”, “red” and “balloons”. Here is how you wrap a scanner around stdin:

Scanner sc = new Scanner(System.in);

You get a scanner by calling one of the eight constructors of java.util.Scanner. The constructors of the scanner class are all private, and the static create() methods call them on your behalf. This leaves the door open for a future update that tries to pool or share instances of scanner (it's not done in the JDK 1.5 library).

If you know what type you are expecting to read from stdin (e.g. you just printed a message saying “Enter your age:”), you can get it like this:

int age = sc.nextInt();

This is not raw I/O that watches the input stream character-by-character. When reading from System.in, you have to type a carriage return before the input is given to your program. There is a nextSomething() method for each primitive type and for three object types, String, java.math.BigDecimal, and java.math.BigInteger.

Here are some of them:

public boolean nextBoolean();
public short nextShort();
public int nextInt();
public double nextDouble();
public String next();  // gets next string
public java.math.BigInteger nextBigInteger();
public java.math.BigDecimal nextBigDecimal(); /* and so on... */

All the nextSomething() methods skip over input that matches the delimiter pattern, and then attempt to return the next token as the stated type. All the nextSomething() methods will block if there is no input ready, which is exactly what you want with console I/O. There is no nextCharacter() because you can just read a character directly using InputStreamReader.read().

If the token cannot be interpreted as a type (e.g. you called sc.nextInt() and the next token is “red”), the method throws a java.util.InputMismatchException, which is a run-time exception. Recall that you do not have to provide a handler for run-time exceptions, but if there is no handler, your program will terminate when the exception occurs.

When a scanner throws an InputMismatchException, the token is not consumed. It remains in the scanner, ready to be retrieved or skipped over by some other method. As well as the nextSomething() methods, there is a hasNextSomething() method for each primitive type and the three object types.

public boolean hasNext();  // has another token of any kind
public boolean hasNextBoolean();
public boolean hasNextShort();
public boolean hasNextInt();
public boolean hasNextDouble();
public boolean hasNextBigInteger();
public boolean hasNextBigDecimal();  /* and so on... */

This provides an easy way to check the input before reading it. Each hasNextSomething() method returns true if the next token in this scanner's input can be interpreted as a value of the Something type. The scanner does not advance past the input that it checks.

Scanners can be wrapped around File objects, as well as around System.in. As an example, if you have a file of doubles separated by whitespace, you can read the whole file by:

Scanner sc2 = Scanner.create(new File("myNumbers.txt"));
while (sc2.hasNextDouble()) {
      double value = sc2.nextDouble();
}

Scanners have more features than described here. In particular, they can skip over or retrieve text that matches a regular expression pattern that you provide. They can scan strings in memory, as well as files and stdin. You can set the delimiters to a pattern other than whitespace (useful when reading a file of comma-separated values). The method takes an argument that is a String or Pattern object containing a regular expression (see Chapter 19) showing all the delimiters. The method is:

sc2.useDelimiter(String)

Scanners also have a notion of locale, so you can set the character that is used to separate groups of thousands in numbers. In the US, this separator is “,” as in “1,000,000”. Some other regions use a different character. There are other locale-specific characters used in java.util.Scanner. You can find them by reading the javadoc page for the class.

Keyboard output

Everyone is used to using the following to print information to the command line:

System.out.println("Your age is: " + age );

image

JDK 1.5 adds a couple of printf() methods to the classes java.io.PrintStream and java.io.PrintWriter. The printf() method is very popular in C. Its first argument is a format string. The format string contains fixed text that you want to be output. It also contains format specifiers that specify how the remaining arguments should be inserted in the text. All format specifiers start with “%” and are followed by one or more other characters giving details of the desired formatting

As an example, you can use the format specifier “%d” to represent that the corresponding argument should be formatted as a decimal integer:

int age = 27;
System.out.printf("Your age is: %d  ", age );

When used to simply output a number as on the line above, there is no benefit to using printf. The power of printf () is seen when you use the format specifiers to format and layout the other arguments that you want to print. You can specify the minimum width for an argument, and the number of decimal places:

System.out.printf("Pi is %7.3f  ", Math.PI);

That specifier “%7.3f” says to format the argument as a floating point number at least 7 characters wide, with 3 decimal places,. The argument, Math.PI here, is autoboxed and given to the method as an Object. The whole variable-arity feature described in chapter 5 was introduced into Java just so the printf() method would have a way to accept a variable number of arguments. Compiling and running the above code yields:

Pi is    3.142

Format specifiers—class java.util.Formatter

The format specifiers really compose a little programming language of their own. Their general format is:

%[ArgumentIndex$][flags][width][.precision]ConversionSpecifier

The square brackets mean that specifier is optional. Not all combinations of specifiers are valid. We'll look at the required field, the conversion specifier, first. Table 17-3 shows some of the most popular conversion specifiers.

Table 17-3. Common conversion specifiers

Char

Meaning

Example

Argument

Output

s

Format as String. If Formattable, print arg.formatTo(), otherwise print arg.toString()

%s

"biff"

biff

d

Format as decimal integer

%d

MyInt

57

f

Format as floating point number (by default, to six decimal places)

%f

Math.PI

3.141593

g

Format as floating point number, and using scientific notation for large exponents

%g

1000000000

1.000000e+09

x

Format as hexadecimal integer

%x

(int) 'A'

41

b

Format as boolean

%b

(i < 10)

true

c

Format as character

%c

'A'

A

h

For debugging. Print the hashcode(), which is usually the address of an object

%h

Math.PI

144d0ce3

n

New line. Use this instead of “ ” for cross-platform support of newlines.

%n

no argument

tX

t indicates a Date conversion. The single character after t indicates what part of a date is needed, e.g. H means hour in the range 00 to 23. B means month name. See the javadoc on java.util.Formatter for full details.

%tB

Calendar.
getInstance()

April

Each tX conversion for a date gets you one or more component of a date, like day, month, year, etc. To get a complete date string, you might need to pass in the Calendar argument more than once, like this:

    Calendar c = Calendar.getInstance();
    System.out.printf("%tD, %tT  ", c, c );
05/06/04, 13:31:28

There are single character specifiers for some commonly used date formats.

    System.out.printf("%tc", c );
Thu May 06 13:31:28 PDT 2004

Other fields in a format specifier String

Recall that the general appearance of a format specifier string (used in printf) is:

%[ArgumentIndex$][flags][width][.precision]ConversionSpecifier

The format specifiers are described at length in the javadoc for class java.util.Formatter. Table 17-3 described the required field, the conversion specifier. Now we give examples showing the optional fields:

  • ArgumentIndex is a number/dollar pair like 1$, 2$, 3$. The number refers to the corresponding argument in the argument list starting at 1. You use this if you want to reorder the arguments, or format the same argument a couple of times in different ways. This is commonly seen with dates, where different conversions get the day, month, and year from the same Calendar object.

    example using ArgumentIndex

    Output

    Calendar c = Calendar.getInstance();
    System.out.printf(
            "1$tB %1$te, %1$tY  ", c);     May 9, 2004

  • Flags adjust the output format. A flag of "^" converts it to upper case. A flag of "-" left justifies the field. Many flags can only be applied to numeric arguments: "+" always includes a sign, "(" puts negative numbers in parentheses.

    example using flag

    output

    System.out.printf("%(d  ", -23);        (23)

  • Width is the minimum number of characters to be written to the output. The asterisks in the example below are so you can see the padding space that has been inserted. Use the width flag to align fields in columns.

    example using width

    Output

    System.out.printf("**%2d**   ", 0);       ** 0**

  • Precision is the number of decimal places for floating point arguments. For non-numeric arguments, this is the maximum width of the field.

    example using precision

    output

    System.out.printf("%.4s  ", "lengthy");   leng

  • Example using the full monty: argument index, flag, width, precision and a conversion specifier:

    example using the full monty

    output

    System.out.printf(
         "**%1$-7.2f**   ", -1.236 );       **-1.24  **

If that isn't ugly enough, there are format specifiers for everything you might want to print: dates, times, numbers, and so on. The format specifiers are similar to those in C, with some changes to accommodate the Java language and exploit some of its features. Like C's sprintf(), Strings may be formatted using the static method String.format():

String printableDate = String.format("%1$tB %1$te, %1$tY  ",
                                           Calendar.getInstance());

Java formatting is more strict than that of C. Java will throw a java.util.IllegalFormatConversionException if a conversion is incompatible with a flag, where C silently ignores the flag. The format specifiers are meant to be readily recognizable to C programmers, but not necessarily 100% compatible with those in C.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.83.199