2.6 input and output
2.6.3 sequential files
FileReader is used
for file input. One of the basic rules of Java is that what works for terminal I/O also works for files. To deal with a file, we do not construct a BufferedReaderobject from anInputStreamReader. Instead, we construct it from a FileReader object, which itself can be constructed by providing a filename.
An example that illustrates these basic ideas is shown in Figure 2.19.
Here, we have a program that will list the contents of the text files that are specified as command-line arguments. The main routine simply steps through the command-line arguments, passing each one to listFile. In
figure 2.18 Read exactly two integers from the same line and output maximum using two Scanners
1 class MaxTestD 2 {
3 public static void main( String [ ] args ) 4 {
5 Scanner in = new Scanner( System.in );
6
7 System.out.println( "Enter 2 ints on one line: " );
8 try 9 {
10 String oneLine = in.nextLine( );
11 Scanner str = new Scanner( oneLine );
12
13 int x = str.nextInt( );
14 int y = str.nextInt( );
15
16 if( !str.hasNext( ) )
17 System.out.println( "Max: " + Math.max( x, y ) );
18 else
19 System.err.println( "Error: extraneous data on the line." );
20 }
21 catch( NoSuchElementException e )
22 { System.err.println( "Error: need two ints" ); } 23 }
24 }
listFile, we construct the FileReader object at line 22, and then use it to construct a Scannerobject,fileIn. At that point, reading is identical to what we have already seen.
After we are done with the file, we must close it; otherwise, we could eventually run out of streams. Note that this cannot be done at the end of the
try block, since an exception could cause a premature exit from the block.
Thus we close the file in a finally block, which is guaranteed to be started
figure 2.19 Program to list contents of a file 1 import java.util.Scanner;
2 import java.io.FileReader;
3 import java.io.IOException;
4
5 public class ListFiles 6 {
7 public static void main( String [ ] args ) 8 {
9 if( args.length == 0 )
10 System.out.println( "No files specified" );
11 for( String fileName : args ) 12 listFile( fileName );
13 } 14
15 public static void listFile( String fileName ) 16 {
17 Scanner fileIn = null;
18
19 System.out.println( "FILE: " + fileName );
20 try 21 {
22 fileIn = new Scanner( new FileReader( fileName ) );
23 while( fileIn.hasNextLine( ) ) 24 {
25 String oneLine = fileIn.nextLine( );
26 System.out.println( oneLine );
27 } 28 }
29 catch( IOException e )
30 { System.out.println( e ); } 31 finally
32 {
33 // Close the stream 34 if( fileIn != null ) 35 fileIn.close( );
36 } 37 } 38 }
1 // Double space files specified on command line.
2
3 import java.io.FileReader;
4 import java.io.FileWriter;
5 import java.io.PrintWriter;
6 import java.io.IOException;
7 import java.util.Scanner;
8
9 public class DoubleSpace 10 {
11 public static void main( String [ ] args ) 12 {
13 for( String fileName : args ) 14 doubleSpace( fileName );
15 } 16
17 public static void doubleSpace( String fileName ) 18 {
19 PrintWriter fileOut = null;
20 Scanner fileIn = null;
21
22 try 23 {
24 fileIn = new Scanner( new FileReader( fileName ) );
25 fileOut = new PrintWriter( new FileWriter( fileName + ".ds" ) );
26
27 while( fileIn.hasNextLine( ) ) 28 {
29 String oneLine = fileIn.nextLine( );
30 fileOut.println( oneLine + "\n" );
31 } 32 }
33 catch( IOException e ) 34 { e.printStackTrace( ); } 35 finally
36 {
37 if( fileOut != null ) 38 fileOut.close( );
39 if( fileIn != null ) 40 fileIn.close( );
41 } 42 } 43 }
figure 2.20
A program to double-space files
whether there are no exceptions, handled exceptions, or unhandled excep-tions. The code to handle the close is complex because
1. fileIn must be declared outside of the try block in order to be visible in the finally block.
2. fileIn must be initialized to null to avoid compiler complaints about a possible uninitialized variable.
3. Prior to calling close, we must check that fileIn is not null to avoid generating a NullPointerException (fileIn would be null
if the file was not found, resulting in an IOException prior to its assignment).
4. In some instances, but not in our example, close might itself throw a checked exception, and would then require an additional
try/catch block.
FileWriter is used for file output.
Formatted file output is similar to file input. FileWriter,PrintWriter, and
println replace FileReader, Scanner, and nextLine, respectively. Figure 2.20 illustrates a program that double-spaces files that are specified on the com-mand line (the resulting files are placed in a file with a .ds extension).
This description of Java I/O, while enough to do basic formatted I/O, hides an interesting object-oriented design that is discussed in more detail in Section 4.5.3.
summary
This chapter examined reference types. A reference is a variable that stores either the memory address where an object resides or the special reference
null. Only objects may be referenced; any object can be referenced by several reference variables. When two references are compared via ==, the result is
true if both references refer to the same object. Similarly, = makes a reference variable reference another object. Only a few other operations are available.
The most significant is the dot operator, which allows the selection of an object’s method or access of its internal data.
Because there are only eight primitive types, virtually everything of con-sequence in Java is an object and is accessed by a reference. This includes
Strings, arrays, exception objects, data and file streams, and a string tokenizer.
TheString is a special reference type because + and += can be used for con-catenation. Otherwise, a Stringis like any other reference; equalsis required to test if the contents of two Strings are identical. An array is a collection of iden-tically typed values. The array is indexed starting at 0, and index range checking is guaranteed to be performed. Arrays can be expanded dynamically by using
newto allocate a larger amount of memory and then copying over individual ele-ments. This process is done automatically by the ArrayList.
Exceptionsare used to signal exceptional events. An exception is signaled by the throwclause; it is propagated until handled by a catchblock that is asso-ciated with a try block. Except for the run-time exceptions and errors, each method must signal the exceptions that it might propagate by using a throwslist.
StringTokenizers are used to parse a String into other Strings. Typically, they are used in conjunction with other input routines. Input is handled by
Scanner and FileReader objects.
The next chapter shows how to design new types by defining a class.
key concepts
aggregateA collection of objects stored in one unit. (37)
array Stores a collection of identically typed objects. (37)
array indexing operator[] Provides access to any element in the array. (37)
ArrayListStores a collection of objects in array-like format, with easy expan-sion via the add method. (42)
call-by-referenceIn many programming languages, means that the formal parameter is a reference to the actual argument. This is the natural effect achieved in Java when call-by-value is used on reference types. (33)
catch block Used to process an exception. (48)
checked exceptionMust be either caught or explicitly allowed to propagate by athrows clause. (50)
command-line argumentAccessed by a parameter to main. (45)
construction For objects, is performed via the new keyword. (31)
dot member operator (.) Allows access to each member of an object. (30)
dynamic array expansionAllows us to make arrays larger if needed. (40)
enhancedfor loopAdded in Java 5, allows iteration through a collection of items. (46)
equals Used to test if the values stored in two objects are the same. (34)
ErrorAn unrecoverable exception. (50)
exception Used to handle exception occurrences, such as errors. (47)
FileReader Used for file input. (56)
FileWriter Used for file output. (59)
finally clauseAlways executed prior to exiting a try/catch sequence. (48)
garbage collectionAutomatic reclaiming of unreferenced memory. (31)
immutableObject whose state cannot change. Specifically, Strings are immutable. (35)
input and output (I/O)Achieved through the use of the java.io package. (51)
java.io Package that is used for nontrivial I/O. (51)
length field Used to determine the size of an array. (38)
length method Used to determine the length of a string. (36)
lhsandrhs Stand for left-hand side and right-hand side, respectively. (32)
multidimensional arrayAn array that is accessed by more than one index. (45)
new Used to construct an object. (31)
null referenceThe value of an object reference that does not refer to any object. (28)
NullPointerExceptionGenerated when attempting to apply a method to a null
reference. (31)
objectA nonprimitive entity. (30)
reference typeAny type that is not a primitive type. (30)
runtime exception Does not have to be handled. Examples include
ArithmeticException and NullPointerException. (49)
ScannerUsed for line-at-a-time input. Also used to extract lines, strings, and primitive types from a single character source such as an input stream or
String. Found in the java.util package. (52, 53)
StringA special object used to store a collection of characters. (35)
string concatenation Performed with + and += operators. (35)
System.in,System.out, and System.errThe predefined I/O streams. (53)
throw clause Used to throw an exception. (51)
throws clause Indicates that a method might propagate an exception. (51)
toString method Converts a primitive type or object to a String. (37)
try block Encloses code that might generate an exception. (48)
common errors
1. For reference types and arrays, =does not make a copy of object values.
Instead, it copies addresses.
2. For reference types and strings, equals should be used instead of == to test if two objects have identical states.
3. Off-by-one errors are common in all languages.
4. Reference types are initialized to nullby default. No object is constructed without calling new. An “uninitialized reference variable” or NullPointer-Exception indicates that you forgot to allocate the object.
5. In Java, arrays are indexed from 0 to N-1, where Nis the array size. How-ever, range checking is performed, so an out-of-bounds array access is detected at run time.
6. Two-dimensional arrays are indexed as A[i][j], not A[i,j].
7. Checked exceptions must either be caught or explicitly allowed to propa-gate with a throws clause.
8. Use" " and not ' ' for outputting a blank.
on the internet
Following are the available files for this chapter. Everything is self-contained, and nothing is used later in the text.
RandomNumbers.java Contains the code for the example in Figure 2.4.
ReadStrings.java Contains the code for the example in Figures 2.6 and 2.7.
ReadStringsWithArrayList.java
Contains the code for the example in Figure 2.8.
MatrixDemo.java Contains the code for the example in Figure 2.9.
Echo.java Contains the code for the example in Figure 2.10.
ForEachDemo.java Illustrates the enhanced for loop.
DivideByTwo.java Contains the code for the example in Figure 2.11.
MaxTest.java Contains the code for the example in Figures 2.15–2.18.
ListFiles.java Contains the code for the example in Figure 2.19.
DoubleSpace.java Contains the code for the example in Figure 2.20.
exercises
IN SHORT
2.1 List the major differences between reference types and primitive types.
2.2 List five operations that can be applied to a reference type.
2.3 What are the differences between an array and ArrayList? 2.4 Describe how exceptions work in Java.
2.5 List the basic operations that can be performed on Strings.
2.6 Explain the role ofnextandhasNextin theScannertype.
IN THEORY
2.7 Ifxandyhave the values of 5 and 7, respectively, what is output by the following?
System.out.println( x + ' ' + y );
System.out.println( x + " " + y );
2.8 The finally block introduces complications in the Java language specification. Write a program to determine what value is returned by
foo and what exception is thrown by bar in Figure 2.21.
IN PRACTICE
2.9 A checksum is the 32-bit integer that is the sum of the Unicode char-acters in a file (we allow silent overflow, but silent overflow is unlikely if all the characters are ASCII). Two identical files have the same checksum. Write a program to compute the checksum of a file that is supplied as a command-line argument.
figure 2.21
Complications caused by the finally block.
public static void foo( ) {
try {
return 0;
} finally {
return 1;
} }
public static void bar( ) { try
{
throw new NullPointerException( );
} finally {
throw new ArithmeticException( );
} }
2.10 Modify the program in Figure 2.19 so that if no command-line argu-ments are given, then the standard input is used.
2.11 Write a method that returns trueifString str1is a prefix of String str2. Do not use any of the general string searching routines except charAt. 2.12 Write a routine that prints the total length of the Strings in a String[]
passed as a parameter. Your routine must work unchanged if the parameter is changed to an ArrayList<String>.
2.13 What is wrong with this code?
public static void resize( int [ ] arr ) {
int [ ] old = arr;
arr = new int[ old.length * 2 + 1 ];
for( int i = 0; i < old.length; i++ ) arr[ i ] = old[ i ];
}
2.14 Implement the following methods, that accept an array of double and return the sum, average, and mode (most common item) in the array.
public static double sum( double [ ] arr ) public static double average( double [ ] arr ) public static double mode( double [ ] arr )
2.15 Implement the following methods, that accept a two-dimensional array of doubleand return the sum, average, and mode (most common item) in the two-dimensional array.
public static double sum( double [ ][ ] arr ) public static double average( double [ ][ ] arr ) public static double mode( double [ ][ ] arr )
2.16 Implement the following methods that reverse an array or ArrayList
ofString.
public static void reverse( String [ ] arr ) public static void reverse( ArrayList<String> arr )
2.17 Implement the following methods that return the minimum of the group of items passed as the parameter. In the case of Strings, the minimum is the alphabetically smallest, as determined by compareTo.
public static int min( int [ ] arr ) public static int min( int [ ][ ] arr ) public static String min( String [ ] arr )
public static String min( ArrayList<String> arr )
2.18 Implement the following method that returns the index of the row that contains the most zeros.
public static int rowWithMostZeros( int [ ] [ ] arr )
2.19 Implement the various hasDuplicatesmethods, which all return true if there are any duplicate entries in the specified group of elements.
public static boolean hasDuplicates( int [ ] arr ) public static boolean hasDuplicates( int [ ][ ] arr ) public static boolean hasDuplicates( String [ ] arr ) public static boolean hasDuplicates( ArrayList<String> arr ) 2.20 Implement both howManymethods, which return the number of
occur-rences of val in arr.
public static int howMany( int [ ] arr, int val ) public static int howMany( int [ ][ ] arr, int val )
2.21 Implement both countChars methods, which return the number of occurrences of ch in str.
public static int countChars( String str, char ch ) public static int countChars( String [ ] str, char ch )
2.22 Using the StringmethodtoLowerCase, which creates a new Stringthat is the lower case equivalent of an existing String (i.e.,str.toLowerCase() returns a lower case equivalent of str, while leaving strunchanged), imple-ment the getLowerCaseandmakeLowerCase methods below. getLowerCase
returns a new collection of Strings, while makeLowerCase modifies the existing collection.
public static String [ ] getLowerCase( String [ ] arr ) public static void makeLowerCase( String [ ] arr )
public static ArrayList<String> getLowerCase( ArrayList<String> arr ) public static void makeLowerCase( ArrayList<String> arr )
2.23 MethodisIncreasingreturns true if in each row of the two-dimensional array, all entries monotonically increase, and in each column all entries also monotonically increase. Implement isIncreasing.
public static boolean isIncreasing( int [ ] [ ] arr )
2.24 Implement method startsWithwhich returns an ArrayListcontaining all the Strings inarr that begin with character ch.
public ArrayList<String> startsWith( String [ ] arr, char ch )
2.25 Implement a split method that returns an array of String contain-ing the tokens of the String. Use a Scanner. The method signature forsplit is
public static String [ ] split( String str )
2.26 An alternative to using a Scanner is to use the split method for a
String. Specifically, in the statement below:
String [ ] arr = str.split( "\\s" );
ifstris "this is a test", then arrwill be an array of length four stor-ing the Strings "this", "is", "a", and "test". Modify the code in Section 2.6.2 to use split instead of a Scanner.
2.27 Both a Scanner andsplit can be configured to use delimiters that are different than the normal whitespace. For instance, in a comma sepa-rated file, the only delimiter is the comma. For split, use "[,]" as the parameter, and for Scanner, at the statement
scan.useDelimiter( "[,]" )
Armed with this information, modify the code in Section 2.6.2 to work for a comma separated line of input.
PROGRAMMING PROJECTS
2.28 Create a data file double1.txtcontaining floating point numbers and suitable for use in Exercise 2.14. Write a method that invokes the functions in that exercise on the data in your file. Make sure there is only 1 item per line and handle all problems.
2.29 Create a data file double2.txt containing floating point numbers in a two dimensional array suitable for use in Exercise 2.15. Write a method that invokes the functions in that exercise on the data in your file. If your code in Exercise 2.15 requires that the two-dimensional array be rectangular, then throw an exception if the data file does not represent a rectangular array, prior to invoking your method.
2.30 Create a data file double3.txt containing floating point numbers in a two dimensional array suitable for use in Exercise 2.15. The numbers in each row should be comma separated. Write a method that invokes the functions in that exercise on the data in your file. If your code in Exercise 2.15 requires that the two-dimensional array be rectangular, then throw an exception if the data file does not represent a rectangu-lar array, prior to invoking your method.
2.31 Write a program that outputs the number of characters, words, and lines in the files that are supplied as command-line arguments.
2.32 In Java, floating-point divide-by-zero is legal and does not result in an exception (instead, it gives a representation of infinity, negative infin-ity, or a special not-a-number symbol).
a. Verify the above description by performing some floating-point divisions.
b. Write a static divide method that takes two parameters and returns their quotient. If the divisor is 0.0, throw an
ArithmeticException. Is a throws clause needed?
c. Write a main program that calls divide and catches the
ArithmeticException. In which method should the catchclause be placed?
2.33 Implement a text file copy program. Include a test to make sure that the source and destination files are different.
2.34 Each line of a file contains a name (as a string) and an age (as an integer).
a. Write a program that outputs the oldest person; in case of ties, output any person.
b. Write a program that outputs the oldest person; in case of ties, output all oldest people (Hint: Maintain the current group of old-est people in an ArrayList.)
2.35 Write a program that calculates the grades for a course. Your program should prompt the user for the name of a file that stores exam scores.
Each line of the file has the following format:
LastName:FirstName:Exam1:Exam2:Exam3
The exams are to be weighted 25% for the first exam, 30% for the second exam, and 45% for the third exam. Based on that, a final grade is to be assigned: A if the total is at least 90, B if it is at last 80, C if it is at least 70, D if it is at least 60, and F otherwise. The highest grade based on the total points is always assigned, so a 75 gets a C.
Your program should output to the terminal a list of students with the let-ter grade, as follows:
LastName FirstName LetterGrade
It should also output to a file, whose name is provided by the user, lines of the form
LastName FirstName Exam1 Exam2 Exam3 TotalPoints LetterGrade
After it is done, it will output the grade distribution. If the input is Doe:John:100:100:100
Pantz:Smartee:80:90:80 Then the terminal output is
Doe John A Pantz Smartee B
And the output file will contain Doe John 100 100 100 100 A Pantz Smartee 80 90 80 83 B A 1
B 1 C 0D 0 F 0
2.36 Modify Exercise 2.35 to use a vary generous scoring scale in which this high exam score is weighted 45%, the next highest score is 30%, and the low exam score is 25%. Otherwise, the specification is identical.
references
More information can be found in the references at the end of Chapter 1.