The Console: System.out, System.in, and System.err

The Console System out, System in, and System err

The console is the default destination for output written to System.out or System.err and the default source of input for System.in. On most platforms the console is the command-line environment from which the Java program was initially launched, perhaps an xterm or a DOS prompt as shown in Figure 1-1. The word console is something of a misnomer, since on Unix systems the console refers to a very specific command-line shell rather than to command-line shells overall.

Figure 1-1. A DOS console on Windows

Many common misconceptions about I/O occur because most programmers' first exposure to I/O is through the console. The console is convenient for quick hacks and toy examples commonly found in textbooks, and I will use it for that in this book, but it's really a very unusual source of input and destination for output, and good Java programs avoid it. It behaves almost, but not completely, unlike anything else you'd want to read from or write to. While consoles make convenient examples in programming texts like this one, they're a horrible user interface and really have little place in modern programs. Users are more comfortable with a well-designed GUI. Furthermore, the console is unreliable across platforms. Many smaller devices such as Palm Pilots and cell phones have no console. Web browsers running applets sometimes provide a console that can be used for output. However, this is hidden by default, normally cannot be used for input, and is not available in all browsers on all platforms.

1.7.1. System.out

System.out is the first instance of the OutputStream class most programmers encounter. In fact, it's often encountered before students know what a class or an output stream is. Specifically, System.out is the static out field of the java.lang.System class. It's an instance of java.io.PrintStream, a subclass of java.io.OutputStream.

System.out corresponds to stdout in Unix or C. Normally, output sent to System.out appears on the console. As a general rule, the console converts the numeric byte data System.out sends to it into ASCII or Latin-1 text. Thus, the following lines write the string "Hello World!" on the console:

byte[] hello = {72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 10, 13}; System.out.write(hello);

 

1.7.2. System.err

Unix and C programmers are familiar with stderr, which is commonly used for error messages. stderr is a separate file pointer from stdout, but often means the same thing. Generally, stderr and stdout both send data to the console, whatever that is. However, stdout and stderr can be redirected to different places. For instance, output can be redirected to a file while error messages still appear on the console.

System.err is Java's version of stderr. Like System.out, System.err is an instance of java.io.PrintStream, a subclass of java.io.OutputStream. System.err is most commonly used inside the catch clause of a TRy/catch block, as shown here:

try { // Do something that may throw an exception. } catch (Exception ex) { System.err.println(ex); }

Finished programs shouldn't have much need for System.err, but it is useful while you're debugging.

Libraries should never print anything on System.err. In general, libraries should not talk to the user at all, unless that is their specific purpose. Instead, libraries should inform the client application of any problems they encounter by throwing an exception or invoking a callback method in some sort of error-handler object. Yes, Xerces, I'm talking to you. (The Xerces XML parser, now built into Java 5 has a really annoying habit of reporting even nonfatal errors by printing them on System.err.)

 

1.7.3. System.in

System.in is the input stream connected to the console, much as System.out is the output stream connected to the console. In Unix or C terms, System.in is stdin and can be redirected from a shell in the same fashion. System.in is the static in field of the java.lang.System class. It's an instance of java.io.InputStream, at least as far as is documented.

Past what's documented, System.in is really a java.io.BufferedInputStream. BufferedInputStream doesn't declare any new methods; it just overrides the ones already declared in java.io.InputStream. Buffered input streams read data in large chunks into a buffer, then parcel it out in requested sizes. This can be more efficient than reading one character at a time. Otherwise, the data is completely transparent to the programmer.

The main significance of this is that bytes are not available to the program at the moment the user types them on System.in. Instead, input enters the program one line at a time. This allows a user typing into the console to backspace over and correct mistakes. Java does not allow you to put the console into "raw mode," wherein each character becomes available as soon as it's typed, including characters such as backspace and delete.

The user types into the console using the platform's default character set, typically ASCII or some superset thereof. The data is converted into numeric bytes when read. For example, if the user types "Hello World!" and hits the Enter key, the following bytes are read from System.in in this order:

72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 10, 13

Many programs that run from the command line and read input from System.in require you to enter the "end of stream" character, also known as the "end of file" or EOF character, to terminate a program normally. How this is entered is platform-dependent. On Unix and the Mac, Ctrl-D generally indicates end of stream. On Windows, Ctrl-Z does. In some cases it may be necessary to type this character alone on a line. That is, you may need to hit Enter/Ctrl-Z or Enter/Ctrl-D before Java will recognize the end of stream.

1.7.4. Redirecting System.out, System.in, and System.err

In a shell, you often redirect stdout, stdin, or stderr. For example, to specify that output from the Java program OptimumBattingOrder goes into the file yankees06.out and that input for that program is read from the file yankees06.tab, you might type:

% java OptimumBattingOrder < yankees06.tab > yankees06.out

Redirection in a DOS shell is the same.

It's sometimes convenient to be able to redirect System.out, System.in, and System.err from inside the running program. The following three static methods in the java.lang.System class do exactly that:

public static void setIn(InputStream in) public static void setOut(PrintStream out) public static void setErr(PrintStream err)

For example, to specify that data written on System.out is sent to the file yankees99.out and that data read from System.in comes from yankees99.tab, you could write:

System.setIn(new FileInputStream("yankees99.tab")); System.setOut(new PrintStream(new FileOutputStream("yankees99.out")));

 

1.7.5. The Console Class // Java 6

While working on Java 6, Sun finally got tired of all the sniping from the Python and Ruby communities about how hard it was to just read a line of input from the console. This is a one liner in most scripting languages, but traditionally it's been a little involved in Java.

The reason reading a line of input from the console is relatively involved in Java compared to some other languages is because in 2006 no one needs to do this outside of a CS 101 course. Real programs use GUIs or the network for user interfaces, not the console, and Java has always been focused on getting real work done rather than enabling toy examples.

Java 6 adds a new java.lang.Console class that provides a few convenience methods for input and output. This class is a singleton. There's never more than one instance of it, and it always applies to the same shell that System.in, System.out, and System.err point to. You retrieve the single instance of this class using the static System.console( ) method like so:

Console theConsole = System.console( );

This method returns null if you're running in an environment such as a cell phone or a web browser that does not have a console.

There are several ways you might use this class. Most importantly, it has a simple readLine( ) method that returns a single string of text from the console, not including the line-break characters:

public String readLine( ) throws IOError

This method returns null on end of stream. It throws an IOError if any I/O problem is encountered. (Again, this is a design bug, and I am trying to convince Sun to fix this before final release. This method should throw an IOException like any normal method if there's a problem.)

You can optionally provide a formatted prompt before reading the line:

public String readLine(String prompt, Object... formatting)

The prompt string is interpreted like any printf( ) string and filled with arguments to its right. All this does is format the prompt. This is not a scanf( ) equivalent. The return value is the same as for the no-args readLine( ) method.

Console also has two readPassword( ) methods:

public char[] readPassword( ) public char[] readPassword(String prompt, Object... formatting)

Unlike readLine( ), these do not echo the characters typed back to the screen. Also note that they return an array of chars rather than a String. When you're finished with the password, you can overwrite the characters in the array with zeros so that the password is not held in memory for longer than it needs to be. This limits the possibility of the password being exposed to memory scanners or stored on the disk due to virtual memory.

For output, Console has two methods, printf( ) and format( ):

public Console format(String format, Object... arguments) public Console printf(String format, Object... arguments)

There is no difference between these two methods. They are synonyms. For example, this code fragment prints a three-column table of the angles between 0 and 360 degrees in degrees, radians, and grads on the console using only printf( ). Each number is exactly five characters wide with one digit after the decimal point.

Console console = System.console( ); for (double degrees = 0.0; degrees < 360.0; degrees++) { double radians = Math.PI * degrees / 180.0; double grads = 400 * degrees / 360; console.printf("%5.1f %5.1f %5.1f ", degrees, radians, grads); }

Here's the start of the output:

0.0 0.0 0.0 1.0 0.0 1.1 2.0 0.0 2.2 3.0 0.1 3.3 ...

Chapter 7 explores printf( ) and its formatting arguments in greater detail.

The console normally buffers all output until a line break is seen. You can force data to be written to the screen even before a line break by invoking the flush( ) method:

formatter.flush( ); formatter.close( );

Finally, if these methods aren't enough for you, you can work directly with the console's associated PrintWriter and Reader:

public PrintWriter writer( ) public Reader reader( )

Chapter 20 explores these two classes.

Example 1-1 is a simple program that uses the Console class to answer a typical homework assignment: ask the user to enter an integer and print the squares of the numbers from 1 to that integer. In keeping with the nature of such programs, I've deliberately left at least three typical student bugs in the code. Identifying and correcting them is left as homework for the reader.

Example 1-1. CS 101 Homework

import java.io.*; class Homework { public static void main(String[] args) { Console console = System.console( ); String input = console.readLine( "Please enter a number between 1 and 10: "); int max = Integer.parseInt(input); for (int i = 1; i < max; i++) { console.printf("%d ", i*i); } } }

Here's what the program looks like when it runs:

C:>java Homework Please enter a number between 1 and 10: 4 1 4 9

Категории