- •Preface
- •1.1 Machine Language
- •1.3 The Java Virtual Machine
- •1.4 Building Blocks of Programs
- •1.5 Object-oriented Programming
- •1.6 The Modern User Interface
- •Quiz on Chapter 1
- •2 Names and Things
- •2.1 The Basic Java Application
- •2.2.1 Variables
- •2.2.2 Types and Literals
- •2.2.3 Variables in Programs
- •2.3.2 Operations on Strings
- •2.3.3 Introduction to Enums
- •2.4 Text Input and Output
- •2.4.1 A First Text Input Example
- •2.4.2 Text Output
- •2.4.3 TextIO Input Functions
- •2.4.4 Formatted Output
- •2.4.5 Introduction to File I/O
- •2.5 Details of Expressions
- •2.5.1 Arithmetic Operators
- •2.5.2 Increment and Decrement
- •2.5.3 Relational Operators
- •2.5.4 Boolean Operators
- •2.5.5 Conditional Operator
- •2.5.7 Type Conversion of Strings
- •2.5.8 Precedence Rules
- •2.6 Programming Environments
- •2.6.1 Java Development Kit
- •2.6.2 Command Line Environment
- •2.6.3 IDEs and Eclipse
- •2.6.4 The Problem of Packages
- •Exercises for Chapter 2
- •Quiz on Chapter 2
- •3 Control
- •3.1 Blocks, Loops, and Branches
- •3.1.1 Blocks
- •3.1.2 The Basic While Loop
- •3.1.3 The Basic If Statement
- •3.2 Algorithm Development
- •3.2.2 The 3N+1 Problem
- •3.2.3 Coding, Testing, Debugging
- •3.3.1 The while Statement
- •3.3.2 The do..while Statement
- •3.3.3 break and continue
- •3.4 The for Statement
- •3.4.1 For Loops
- •3.4.2 Example: Counting Divisors
- •3.4.3 Nested for Loops
- •3.5 The if Statement
- •3.5.1 The Dangling else Problem
- •3.5.2 The if...else if Construction
- •3.5.3 If Statement Examples
- •3.5.4 The Empty Statement
- •3.6 The switch Statement
- •3.6.1 The Basic switch Statement
- •3.6.2 Menus and switch Statements
- •3.6.3 Enums in switch Statements
- •3.7.1 Exceptions
- •3.7.2 try..catch
- •3.7.3 Exceptions in TextIO
- •Exercises for Chapter 3
- •Quiz on Chapter 3
- •4 Subroutines
- •4.1 Black Boxes
- •4.2.2 Calling Subroutines
- •4.2.3 Subroutines in Programs
- •4.2.4 Member Variables
- •4.3 Parameters
- •4.3.1 Using Parameters
- •4.3.2 Formal and Actual Parameters
- •4.3.3 Overloading
- •4.3.4 Subroutine Examples
- •4.3.5 Throwing Exceptions
- •4.3.6 Global and Local Variables
- •4.4 Return Values
- •4.4.1 The return statement
- •4.4.2 Function Examples
- •4.4.3 3N+1 Revisited
- •4.5 APIs, Packages, and Javadoc
- •4.5.1 Toolboxes
- •4.5.3 Using Classes from Packages
- •4.5.4 Javadoc
- •4.6 More on Program Design
- •4.6.1 Preconditions and Postconditions
- •4.6.2 A Design Example
- •4.6.3 The Program
- •4.7 The Truth About Declarations
- •4.7.1 Initialization in Declarations
- •4.7.2 Named Constants
- •4.7.3 Naming and Scope Rules
- •Exercises for Chapter 4
- •Quiz on Chapter 4
- •5 Objects and Classes
- •5.1.1 Objects, Classes, and Instances
- •5.1.2 Fundamentals of Objects
- •5.1.3 Getters and Setters
- •5.2 Constructors and Object Initialization
- •5.2.1 Initializing Instance Variables
- •5.2.2 Constructors
- •5.2.3 Garbage Collection
- •5.3 Programming with Objects
- •5.3.2 Wrapper Classes and Autoboxing
- •5.4 Programming Example: Card, Hand, Deck
- •5.4.1 Designing the classes
- •5.4.2 The Card Class
- •5.4.3 Example: A Simple Card Game
- •5.5.1 Extending Existing Classes
- •5.5.2 Inheritance and Class Hierarchy
- •5.5.3 Example: Vehicles
- •5.5.4 Polymorphism
- •5.5.5 Abstract Classes
- •5.6 this and super
- •5.6.1 The Special Variable this
- •5.6.2 The Special Variable super
- •5.6.3 Constructors in Subclasses
- •5.7 Interfaces, Nested Classes, and Other Details
- •5.7.1 Interfaces
- •5.7.2 Nested Classes
- •5.7.3 Anonymous Inner Classes
- •5.7.5 Static Import
- •5.7.6 Enums as Classes
- •Exercises for Chapter 5
- •Quiz on Chapter 5
- •6 Introduction to GUI Programming
- •6.1 The Basic GUI Application
- •6.1.1 JFrame and JPanel
- •6.1.2 Components and Layout
- •6.1.3 Events and Listeners
- •6.2 Applets and HTML
- •6.2.1 JApplet
- •6.2.2 Reusing Your JPanels
- •6.2.3 Basic HTML
- •6.2.4 Applets on Web Pages
- •6.3 Graphics and Painting
- •6.3.1 Coordinates
- •6.3.2 Colors
- •6.3.3 Fonts
- •6.3.4 Shapes
- •6.3.5 Graphics2D
- •6.3.6 An Example
- •6.4 Mouse Events
- •6.4.1 Event Handling
- •6.4.2 MouseEvent and MouseListener
- •6.4.3 Mouse Coordinates
- •6.4.4 MouseMotionListeners and Dragging
- •6.4.5 Anonymous Event Handlers
- •6.5 Timer and Keyboard Events
- •6.5.1 Timers and Animation
- •6.5.2 Keyboard Events
- •6.5.3 Focus Events
- •6.5.4 State Machines
- •6.6 Basic Components
- •6.6.1 JButton
- •6.6.2 JLabel
- •6.6.3 JCheckBox
- •6.6.4 JTextField and JTextArea
- •6.6.5 JComboBox
- •6.6.6 JSlider
- •6.7 Basic Layout
- •6.7.1 Basic Layout Managers
- •6.7.2 Borders
- •6.7.3 SliderAndComboBoxDemo
- •6.7.4 A Simple Calculator
- •6.7.5 Using a null Layout
- •6.7.6 A Little Card Game
- •6.8 Menus and Dialogs
- •6.8.1 Menus and Menubars
- •6.8.2 Dialogs
- •6.8.3 Fine Points of Frames
- •6.8.4 Creating Jar Files
- •Exercises for Chapter 6
- •Quiz on Chapter 6
- •7 Arrays
- •7.1 Creating and Using Arrays
- •7.1.1 Arrays
- •7.1.2 Using Arrays
- •7.1.3 Array Initialization
- •7.2 Programming With Arrays
- •7.2.1 Arrays and for Loops
- •7.2.3 Array Types in Subroutines
- •7.2.4 Random Access
- •7.2.5 Arrays of Objects
- •7.2.6 Variable Arity Methods
- •7.3 Dynamic Arrays and ArrayLists
- •7.3.1 Partially Full Arrays
- •7.3.2 Dynamic Arrays
- •7.3.3 ArrrayLists
- •7.3.4 Parameterized Types
- •7.3.5 Vectors
- •7.4 Searching and Sorting
- •7.4.1 Searching
- •7.4.2 Association Lists
- •7.4.3 Insertion Sort
- •7.4.4 Selection Sort
- •7.4.5 Unsorting
- •7.5.3 Example: Checkers
- •Exercises for Chapter 7
- •Quiz on Chapter 7
- •8 Correctness and Robustness
- •8.1 Introduction to Correctness and Robustness
- •8.1.1 Horror Stories
- •8.1.2 Java to the Rescue
- •8.1.3 Problems Remain in Java
- •8.2 Writing Correct Programs
- •8.2.1 Provably Correct Programs
- •8.2.2 Robust Handling of Input
- •8.3 Exceptions and try..catch
- •8.3.1 Exceptions and Exception Classes
- •8.3.2 The try Statement
- •8.3.3 Throwing Exceptions
- •8.3.4 Mandatory Exception Handling
- •8.3.5 Programming with Exceptions
- •8.4 Assertions
- •8.5 Introduction to Threads
- •8.5.1 Creating and Running Threads
- •8.5.2 Operations on Threads
- •8.5.4 Wait and Notify
- •8.5.5 Volatile Variables
- •8.6 Analysis of Algorithms
- •Exercises for Chapter 8
- •Quiz on Chapter 8
- •9.1 Recursion
- •9.1.1 Recursive Binary Search
- •9.1.2 Towers of Hanoi
- •9.1.3 A Recursive Sorting Algorithm
- •9.1.4 Blob Counting
- •9.2 Linked Data Structures
- •9.2.1 Recursive Linking
- •9.2.2 Linked Lists
- •9.2.3 Basic Linked List Processing
- •9.2.4 Inserting into a Linked List
- •9.2.5 Deleting from a Linked List
- •9.3 Stacks, Queues, and ADTs
- •9.3.1 Stacks
- •9.3.2 Queues
- •9.4 Binary Trees
- •9.4.1 Tree Traversal
- •9.4.2 Binary Sort Trees
- •9.4.3 Expression Trees
- •9.5 A Simple Recursive Descent Parser
- •9.5.1 Backus-Naur Form
- •9.5.2 Recursive Descent Parsing
- •9.5.3 Building an Expression Tree
- •Exercises for Chapter 9
- •Quiz on Chapter 9
- •10.1 Generic Programming
- •10.1.1 Generic Programming in Smalltalk
- •10.1.2 Generic Programming in C++
- •10.1.3 Generic Programming in Java
- •10.1.4 The Java Collection Framework
- •10.1.6 Equality and Comparison
- •10.1.7 Generics and Wrapper Classes
- •10.2 Lists and Sets
- •10.2.1 ArrayList and LinkedList
- •10.2.2 Sorting
- •10.2.3 TreeSet and HashSet
- •10.2.4 EnumSet
- •10.3 Maps
- •10.3.1 The Map Interface
- •10.3.2 Views, SubSets, and SubMaps
- •10.3.3 Hash Tables and Hash Codes
- •10.4 Programming with the Collection Framework
- •10.4.1 Symbol Tables
- •10.4.2 Sets Inside a Map
- •10.4.3 Using a Comparator
- •10.4.4 Word Counting
- •10.5 Writing Generic Classes and Methods
- •10.5.1 Simple Generic Classes
- •10.5.2 Simple Generic Methods
- •10.5.3 Type Wildcards
- •10.5.4 Bounded Types
- •Exercises for Chapter 10
- •Quiz on Chapter 10
- •11 Files and Networking
- •11.1 Streams, Readers, and Writers
- •11.1.1 Character and Byte Streams
- •11.1.2 PrintWriter
- •11.1.3 Data Streams
- •11.1.4 Reading Text
- •11.1.5 The Scanner Class
- •11.1.6 Serialized Object I/O
- •11.2 Files
- •11.2.1 Reading and Writing Files
- •11.2.2 Files and Directories
- •11.2.3 File Dialog Boxes
- •11.3 Programming With Files
- •11.3.1 Copying a File
- •11.3.2 Persistent Data
- •11.3.3 Files in GUI Programs
- •11.3.4 Storing Objects in Files
- •11.4 Networking
- •11.4.1 URLs and URLConnections
- •11.4.2 TCP/IP and Client/Server
- •11.4.3 Sockets
- •11.4.4 A Trivial Client/Server
- •11.4.5 A Simple Network Chat
- •11.5 Network Programming and Threads
- •11.5.1 A Threaded GUI Chat Program.
- •11.5.2 A Multithreaded Server
- •11.5.3 Distributed Computing
- •11.6 A Brief Introduction to XML
- •11.6.1 Basic XML Syntax
- •11.6.2 XMLEncoder and XMLDecoder
- •11.6.3 Working With the DOM
- •Exercises for Chapter 11
- •Quiz on Chapter 11
- •12 Advanced GUI Programming
- •12.1 Images and Resources
- •12.1.2 Working With Pixels
- •12.1.3 Resources
- •12.1.4 Cursors and Icons
- •12.1.5 Image File I/O
- •12.2 Fancier Graphics
- •12.2.1 Measuring Text
- •12.2.2 Transparency
- •12.2.3 Antialiasing
- •12.2.4 Strokes and Paints
- •12.2.5 Transforms
- •12.3 Actions and Buttons
- •12.3.1 Action and AbstractAction
- •12.3.2 Icons on Buttons
- •12.3.3 Radio Buttons
- •12.3.4 Toolbars
- •12.3.5 Keyboard Accelerators
- •12.3.6 HTML on Buttons
- •12.4 Complex Components and MVC
- •12.4.1 Model-View-Controller
- •12.4.2 Lists and ListModels
- •12.4.3 Tables and TableModels
- •12.4.4 Documents and Editors
- •12.4.5 Custom Components
- •12.5 Finishing Touches
- •12.5.1 The Mandelbrot Set
- •12.5.2 Design of the Program
- •12.5.3 Internationalization
- •12.5.4 Events, Events, Events
- •12.5.5 Custom Dialogs
- •12.5.6 Preferences
- •Exercises for Chapter 12
- •Quiz on Chapter 12
- •Appendix: Source Files
CHAPTER 11. FILES AND NETWORKING |
548 |
||
public void writeFile() { |
|
||
if (fileDialog == null) |
|
||
fileDialog = new JFileChooser(); // (fileDialog is an instance variable) |
|||
File selectedFile = new File("(default file name)"); |
|||
fileDialog.setSelectedFile(selectedFile); |
// Specify a default file name. |
||
fileDialog.setDialogTitle("Select File for Writing"); |
|||
int option = fileDialog.showSaveDialog(this); |
|||
if (option != JFileChooser.APPROVE |
|
OPTION) |
|
return; // User canceled or clicked the dialog’s close box. |
|||
selectedFile = fileDialog.getSelectedFile(); |
|||
if (selectedFile.exists()) { // Ask the user whether to replace the file. |
|||
int response = JOptionPane.showConfirmDialog( this, "The file \"" + selectedFile.getName()
+ "\" already exists.\nDo you want to replace it?", "Confirm Save",
JOptionPane.YES NO OPTION, JOptionPane.WARNING MESSAGE );
if (response != JOptionPane.YES OPTION)
return; // User does not want to replace the file.
}
PrintWriter out; // (or use some other wrapper class) try {
FileWriter stream = new FileWriter(selectedFile); // (or FileOutputStream) out = new PrintWriter( stream );
}
catch (Exception e) { JOptionPane.showMessageDialog(this,
"Sorry, but an error occurred while trying to open the file:\n" + e); return;
}
try {
.
. // Write data to the output stream, out.
.
out.close();
if (out.checkError()) // (need to check for errors in PrintWriter) throw new IOException("Error check failed.");
}
catch (Exception e) { JOptionPane.showMessageDialog(this,
"Sorry, but an error occurred while trying to write the data:\n" + e);
}
}
The readFile() and writeFile() routines presented here can be used, with just a few changes, when you need to read or write a file in a GUI program. We’ll look at some more complete examples of using files and file dialogs in the next section.
11.3 Programming With Files
In this section, we look at several programming examples that work with files, using the (online) techniques that were introduced in Section 11.1 and Section 11.2.
CHAPTER 11. FILES AND NETWORKING |
549 |
11.3.1Copying a File
As a first example, we look at a simple command-line program that can make a copy of a file. Copying a file is a pretty common operation, and every operating system already has a command for doing it. However, it is still instructive to look at a Java program that does the same thing. Many file operations are similar to copying a file, except that the data from the input file is processed in some way before it is written to the output file. All such operations can be done by programs with the same general form.
Since the program should be able to copy any file, we can’t assume that the data in the file is in human-readable form. So, we have to use InputStream and OutputStream to operate on the file rather than Reader and Writer. The program simply copies all the data from the InputStream to the OutputStream, one byte at a time. If source is the variable that refers to the InputStream, then the function source.read() can be used to read one byte. This function returns the value -1 when all the bytes in the input file have been read. Similarly, if copy refers to the OutputStream, then copy.write(b) writes one byte to the output file. So, the heart of the program is a simple while loop. As usual, the I/O operations can throw exceptions, so this must be done in a try..catch statement:
while(true) {
int data = source.read(); if (data < 0)
break;
copy.write(data);
}
The file-copy command in an operating system such as UNIX uses command line arguments to specify the names of the files. For example, the user might say “copy original.dat backup.dat” to copy an existing file, original.dat, to a file named backup.dat. Commandline arguments can also be used in Java programs. The command line arguments are stored in the array of strings, args, which is a parameter to the main() routine. The program can retrieve the command-line arguments from this array. (See Subsection 7.2.3.) For example, if the program is named CopyFile and if the user runs the program with the command “java CopyFile work.dat oldwork.dat”, then in the program, args[0] will be the string "work.dat" and args[1] will be the string "oldwork.dat". The value of args.length tells the program how many command-line arguments were specified by the user.
My CopyFile program gets the names of the files from the command-line arguments. It prints an error message and exits if the file names are not specified. To add a little interest, there are two ways to use the program. The command line can simply specify the two file names. In that case, if the output file already exists, the program will print an error message and end. This is to make sure that the user won’t accidently overwrite an important file. However, if the command line has three arguments, then the first argument must be “-f” while the second and third arguments are file names. The -f is a command-line option, which is meant to modify the behavior of the program. The program interprets the -f to mean that it’s OK to overwrite an existing program. (The “f” stands for “force,” since it forces the file to be copied in spite of what would otherwise have been considered an error.) You can see in the source code how the command line arguments are interpreted by the program:
import java.io.*;
/**
* Makes a copy of a file. The original file and the name of the
CHAPTER 11. FILES AND NETWORKING |
550 |
*copy must be given as command-line arguments. In addition, the
*first command-line argument can be "-f"; if present, the program
*will overwrite an existing file; if not, the program will report
*an error and end if the output file already exists. The number
*of bytes that are copied is reported.
*/
public class CopyFile {
public static void main(String[] args) {
String sourceName; |
// |
Name of the source |
file, |
|
// |
as specified on the command line. |
|
String copyName; |
// |
Name of the copy, |
|
|
// |
as specified on the command line. |
|
InputStream source; |
// |
Stream for reading from the source file. |
|
OutputStream copy; |
// |
Stream for writing the copy. |
|
boolean force; // This |
is set to true if the "-f" option |
||
// |
is specified on the command line. |
||
int byteCount; // Number of bytes copied from the source file.
/* Get file names from the command line and check for the presence of the -f option. If the command line is not one of the two possible legal forms, print an error message and end this program. */
if (args.length == 3 && args[0].equalsIgnoreCase("-f")) { sourceName = args[1];
copyName = args[2]; force = true;
}
else if (args.length == 2) { sourceName = args[0]; copyName = args[1]; force = false;
}
else { System.out.println(
"Usage: java CopyFile <source-file> <copy-name>"); System.out.println(
" or java CopyFile -f <source-file> <copy-name>");
return;
}
/* Create the input stream. If an error occurs, end the program. */
try {
source = new FileInputStream(sourceName);
}
catch (FileNotFoundException e) {
System.out.println("Can’t find file \"" + sourceName + "\"."); return;
}
/* If the output file already exists and the -f option was not specified, print an error message and end the program. */
File file = new File(copyName);
CHAPTER 11. FILES AND NETWORKING |
551 |
if (file.exists() && force == false) { System.out.println(
"Output file exists. Use the -f option to replace it."); return;
}
/* Create the output stream. If an error occurs, end the program. */
try {
copy = new FileOutputStream(copyName);
}
catch (IOException e) {
System.out.println("Can’t open output file \"" + copyName + "\"."); return;
}
/* Copy one byte at a time from the input stream to the output stream, ending when the read() method returns -1 (which is
the signal that the end of the stream has been reached). If any error occurs, print an error message. Also print a message if the file has been copied successfully. */
byteCount = 0;
try {
while (true) {
int data = source.read(); if (data < 0)
break;
copy.write(data);
byteCount++;
}
source.close();
copy.close();
System.out.println("Successfully copied " + byteCount + " bytes.");
}
catch (Exception e) {
System.out.println("Error occurred while copying. "
+ byteCount + " bytes copied."); System.out.println("Error: " + e);
}
}// end main()
}// end class CopyFile
11.3.2Persistent Data
Once a program ends, any data that was stored in variables and objects in the program is gone. In many cases, it would be useful to have some of that data stick around so that it will be available when the program is run again. The problem is, how to make the data persistent between runs of the program? The answer, of course, is to store the data in a file (or, for some applications, in a database—but the data in a database is itself stored in files).
Consider a “phone book” program that allows the user to keep track of a list of names and associated phone numbers. The program would make no sense at all if the user had to create
CHAPTER 11. FILES AND NETWORKING |
552 |
the whole list from scratch each time the program is run. It would make more sense to think of the phone book as a persistent collection of data, and to think of the program as an interface to that collection of data. The program would allow the user to look up names in the phone book and to add new entries. Any changes that are made should be preserved after the program ends.
The sample program PhoneDirectoryFileDemo.java is a very simple implementation of this idea. It is meant only as an example of file use; the phone book that it implements is a “toy” version that is not meant to be taken seriously. This program stores the phone book data in a file named “.phone book demo” in the user’s home directory. To find the user’s home directory, it uses the System.getProperty() method that was mentioned in Subsection 11.2.2. When the program starts, it checks whether the file already exists. If it does, it should contain the user’s phone book, which was saved in a previous run of the program, so the data from the file is read and entered into a TreeMap named phoneBook that represents the phone book while the program is running. (See Subsection 10.3.1.) In order to store the phone book in a file, some decision must be made about how the data in the phone book will be represented. For this example, I chose a simple representation in which each line of the file contains one entry consisting of a name and the associated phone number. A percent sign (’%’) separates the name from the number. The following code at the beginning of the program will read the phone book data file, if it exists and has the correct format:
File userHomeDirectory = new File( System.getProperty("user.home") ); File dataFile = new File( userHomeDirectory, ".phone book data" );
if ( ! dataFile.exists() ) {
System.out.println("No phone book data file found."); System.out.println("A new one will be created."); System.out.println("File name: " + dataFile.getAbsolutePath());
}
else {
System.out.println("Reading phone book data..."); try {
Scanner scanner = new Scanner( dataFile ); while (scanner.hasNextLine()) {
// Read one line from the file, containing one name/number pair. String phoneEntry = scanner.nextLine();
int separatorPosition = phoneEntry.indexOf(’%’); if (separatorPosition == -1)
throw new IOException("File is not a phonebook data file."); name = phoneEntry.substring(0, separatorPosition);
number = phoneEntry.substring(separatorPosition+1); phoneBook.put(name,number);
}
}
catch (IOException e) {
System.out.println("Error in phone book data file."); System.out.println("File name: " + dataFile.getAbsolutePath()); System.out.println("This program cannot continue."); System.exit(1);
}
}
