To make our example programs more interesting, we want to accept input and properly format the program output. Of course, modern programs use a GUI for collecting user input. However, programming such an interface requires more tools and techniques than we have at our disposal at this time. Our first order of business is to become more familiar with the Java programming language, so we use the humble console for input and output.
1. Reading Input
You saw that it is easy to print output to the “standard output stream” (that is, the console window) just by calling System.out.println. Reading from the “standard input stream” System.in isn’t quite as simple. To read console input, you first construct a Scanner that is attached to System.in:
Scanner in = new Scanner(System.in);
(We discuss constructors and the new operator in detail in Chapter 4.)
Now you can use the various methods of the Scanner class to read input. For example, the nextLine method reads a line of input.
System.out.print(“What is your name?”);
String name = in.nextLine();
Here, we use the nextLine method because the input might contain spaces. To read a single word (delimited by whitespace), call
String firstName = in.next();
To read an integer, use the nextInt method.
System.out.print(“How old are you?”);
int age = in.nextInt();
Similarly, the nextDouble method reads the next floating-point number.
The program in Listing 3.2 asks for the user’s name and age and then prints a message like
Hello, Cay. Next year, you’ll be 57
Finally, note the line
import java.util.*;
at the beginning of the program. The Scanner class is defined in the java.util package. Whenever you use a class that is not defined in the basic java.lang package, you need to use an import directive. We look at packages and import directives in more detail in Chapter 4.
2. Formatting Output
You can print a number x to the console with the statement System,out,print(x). That command will print x with the maximum number of nonzero digits for that type. For example,
double x = 10000.0 / 3.0;
System.out.print(x);
prints
3333.3333333333335
That is a problem if you want to display, for example, dollars and cents.
In early versions of Java, formatting numbers was a bit of a hassle. Fortunately, Java 5 brought back the venerable printf method from the C library. For example, the call
System.out.printf(“%8,2f”, x);
prints x with a field width of 8 characters and a precision of 2 characters. That is, the printout contains a leading space and the seven characters
3333.33
You can supply multiple parameters to printf. For example:
System.out.printf(“Hello, %s. Next year, you’ll be %d”, name, age);
Each of the format specifiers that start with a % character is replaced with the corresponding argument. The conversion character that ends a format specifier indicates the type of the value to be formatted: f is a floating-point number, s a string, and d a decimal integer. Table 3.5 shows all conversion characters.
In addition, you can specify flags that control the appearance of the formatted output. Table 3.6 shows all flags. For example, the comma flag adds group separators. That is,
System.out.printf(“%,.2f”, 10000.0 / 3.0);
prints
3,333.33
You can use multiple flags, for example “%,(.2f” to use group separators and enclose negative numbers in parentheses.
You can use the static String.format method to create a formatted string without printing it:
String message = String.format(“Hello, %s. Next year, you’ll be %d”, name, age);
In the interest of completeness, we briefly discuss the date and time formatting options of the printf method. For new code, you should use the methods of the java.time package described in Chapter 6 of Volume II. But you may encounter the Date class and the associated formatting options in legacy code. The format consists of two letters, starting with t and ending in one of the letters of Table 3.7; for example,
System.out.printf(“%tc”, new Date());
prints the current date and time in the format
Mon Feb 09 18:05:19 PST 2015
As you can see in Table 3.7, some of the formats yield only a part of a given date—for example, just the day or just the month. It would be a bit silly if you had to supply the date multiple times to format each part. For that reason, a format string can indicate the index of the argument to be formatted. The index must immediately follow the %, and it must be terminated by a $. For example,
System.out.printf(“%1$s %2$tB %2$te, %2$tY”, “Due date:”, new Date());
prints
Due date: February 9, 2015
Alternatively, you can use the < flag. It indicates that the same argument as in the preceding format specification should be used again. That is, the statement
System.out.printf(“%s %tB %<te, %<tY”, “Due date:”, new Date());
yields the same output as the preceding statement.
You have now seen all features of the printf method. Figure 3.6 shows a syntax diagram for format specifiers.
3. File Input and Output
To read from a file, construct a Scanner object like this:
Scanner in = new Scanner(Path.of(“myfite.txt”), StandardCharsets.UTF_8);
If the file name contains backslashes, remember to escape each of them with an additional backslash: “c:\\mydirectory\\myfite.txt”.
Now you can read from the file, using any of the Scanner methods that we already described.
To write to a file, construct a PrintWriter object. In the constructor, supply the file name and the character encoding:
PrintWriter out = new PrintWriter(“myfite.txt”, StandardCharsets.UTF_8);
If the file does not exist, it is created. You can use the print, printtn, and printf commands as you did when printing to System.out.
As you saw, you can access files just as easily as you can use System.in and System.out. There is just one catch: If you construct a Scanner with a file that does not exist or a PrintWriter with a file name that cannot be created, an exception occurs. The Java compiler considers these exceptions to be more serious than a “divide by zero” exception, for example. In Chapter 7, you will learn various ways of handling exceptions. For now, you should simply tell the compiler that you are aware of the possibility of an “input/output” exception. You do this by tagging the main method with a throws clause, like this:
public static void main(String[] args) throws IOException
{
Scanner in = new Scanner(Path.of(“myfile.txt”), StandardCharsets.UTF_8);
…
}
You have now seen how to read and write files that contain textual data. For more advanced topics, such as dealing with different character encodings, processing binary data, reading directories, and writing zip files, turn to Chapter 2 of Volume II.
Source: Horstmann Cay S. (2019), Core Java. Volume I – Fundamentals, Pearson; 11th edition.