You are previewing Learning Java, 4th Edition.

Learning Java, 4th Edition

Cover of Learning Java, 4th Edition by Daniel Leuck... Published by O'Reilly Media, Inc.
  1. Learning Java
  2. Preface
    1. Who Should Read This Book
    2. New Developments
      1. New in This Edition (Java 6 and 7)
    3. Using This Book
    4. Online Resources
    5. Conventions Used in This Book
    6. Using Code Examples
    7. Safari® Books Online
    8. How to Contact Us
    9. Acknowledgments
  3. 1. A Modern Language
    1. Enter Java
      1. Java’s Origins
      2. Growing Up
    2. A Virtual Machine
    3. Java Compared with Other Languages
    4. Safety of Design
      1. Simplify, Simplify, Simplify...
      2. Type Safety and Method Binding
      3. Incremental Development
      4. Dynamic Memory Management
      5. Error Handling
      6. Threads
      7. Scalability
    5. Safety of Implementation
      1. The Verifier
      2. Class Loaders
      3. Security Managers
    6. Application and User-Level Security
    7. A Java Road Map
      1. The Past: Java 1.0–Java 1.6
      2. The Present: Java 7
      3. The Future
      4. Availability
  4. 2. A First Application
    1. Java Tools and Environment
    2. Configuring Eclipse and Creating a Project
      1. Importing the Learning Java Examples
    3. HelloJava
      1. Classes
      2. The main() Method
      3. Classes and Objects
      4. Variables and Class Types
      5. HelloComponent
      6. Inheritance
      7. The JComponent Class
      8. Relationships and Finger Pointing
      9. Package and Imports
      10. The paintComponent() Method
    4. HelloJava2: The Sequel
      1. Instance Variables
      2. Constructors
      3. Events
      4. The repaint() Method
      5. Interfaces
    5. HelloJava3: The Button Strikes!
      1. Method Overloading
      2. Components
      3. Containers
      4. Layout
      5. Subclassing and Subtypes
      6. More Events and Interfaces
      7. Color Commentary
      8. Static Members
      9. Arrays
      10. Our Color Methods
    6. HelloJava4: Netscape’s Revenge
      1. Threads
      2. The Thread Class
      3. The Runnable Interface
      4. Starting the Thread
      5. Running Code in the Thread
      6. Exceptions
      7. Synchronization
  5. 3. Tools of the Trade
    1. JDK Environment
    2. The Java VM
    3. Running Java Applications
      1. System Properties
    4. The Classpath
      1. javap
    5. The Java Compiler
    6. JAR Files
      1. File Compression
      2. The jar Utility
      3. The pack200 Utility
    7. Policy Files
      1. The Default Security Manager
      2. The policytool Utility
      3. Using a Policy File with the Default Security Manager
  6. 4. The Java Language
    1. Text Encoding
      1. Javadoc Comments
    3. Types
      1. Primitive Types
      2. Reference Types
      3. A Word About Strings
    4. Statements and Expressions
      1. Statements
      2. Expressions
    5. Exceptions
      1. Exceptions and Error Classes
      2. Exception Handling
      3. Bubbling Up
      4. Stack Traces
      5. Checked and Unchecked Exceptions
      6. Throwing Exceptions
      7. try Creep
      8. The finally Clause
      9. Try with Resources
      10. Performance Issues
    6. Assertions
      1. Enabling and Disabling Assertions
      2. Using Assertions
    7. Arrays
      1. Array Types
      2. Array Creation and Initialization
      3. Using Arrays
      4. Anonymous Arrays
      5. Multidimensional Arrays
      6. Inside Arrays
  7. 5. Objects in Java
    1. Classes
      1. Accessing Fields and Methods
      2. Static Members
    2. Methods
      1. Local Variables
      2. Shadowing
      3. Static Methods
      4. Initializing Local Variables
      5. Argument Passing and References
      6. Wrappers for Primitive Types
      7. Autoboxing and Unboxing of Primitives
      8. Variable-Length Argument Lists
      9. Method Overloading
    3. Object Creation
      1. Constructors
      2. Working with Overloaded Constructors
      3. Static and Nonstatic Initializer Blocks
    4. Object Destruction
      1. Garbage Collection
      2. Finalization
      3. Weak and Soft References
    5. Enumerations
      1. Enum Values
      2. Customizing Enumerations
  8. 6. Relationships Among Classes
    1. Subclassing and Inheritance
      1. Shadowed Variables
      2. Overriding Methods
      3. Special References: this and super
      4. Casting
      5. Using Superclass Constructors
      6. Full Disclosure: Constructors and Initialization
      7. Abstract Methods and Classes
    2. Interfaces
      1. Interfaces as Callbacks
      2. Interface Variables
      3. Subinterfaces
    3. Packages and Compilation Units
      1. Compilation Units
      2. Package Names
      3. Class Visibility
      4. Importing Classes
    4. Visibility of Variables and Methods
      1. Basic Access Modifiers
      2. Subclasses and Visibility
      3. Interfaces and Visibility
    5. Arrays and the Class Hierarchy
      1. ArrayStoreException
    6. Inner Classes
      1. Inner Classes as Adapters
      2. Inner Classes Within Methods
  9. 7. Working with Objects and Classes
    1. The Object Class
      1. Equality and Equivalence
      2. Hashcodes
      3. Cloning Objects
    2. The Class Class
    3. Reflection
      1. Modifiers and Security
      2. Accessing Fields
      3. Accessing Methods
      4. Accessing Constructors
      5. What About Arrays?
      6. Accessing Generic Type Information
      7. Accessing Annotation Data
      8. Dynamic Interface Adapters
      9. What Is Reflection Good For?
    4. Annotations
      1. Using Annotations
      2. Standard Annotations
      3. The apt Tool
  10. 8. Generics
    1. Containers: Building a Better Mousetrap
      1. Can Containers Be Fixed?
    2. Enter Generics
      1. Talking About Types
    3. “There Is No Spoon”
      1. Erasure
      2. Raw Types
    4. Parameterized Type Relationships
      1. Why Isn’t a List<Date> a List<Object>?
    5. Casts
    6. Writing Generic Classes
      1. The Type Variable
      2. Subclassing Generics
      3. Exceptions and Generics
      4. Parameter Type Limitations
    7. Bounds
      1. Erasure and Bounds (Working with Legacy Code)
    8. Wildcards
      1. A Supertype of All Instantiations
      2. Bounded Wildcards
      3. Thinking Outside the Container
      4. Lower Bounds
      5. Reading, Writing, and Arithmetic
      6. <?>, <Object>, and the Raw Type
      7. Wildcard Type Relationships
    9. Generic Methods
      1. Generic Methods Introduced
      2. Type Inference from Arguments
      3. Type Inference from Assignment Context
      4. Explicit Type Invocation
      5. Wildcard Capture
      6. Wildcard Types Versus Generic Methods
    10. Arrays of Parameterized Types
      1. Using Array Types
      2. What Good Are Arrays of Generic Types?
      3. Wildcards in Array Types
    11. Case Study: The Enum Class
    12. Case Study: The sort() Method
    13. Conclusion
  11. 9. Threads
    1. Introducing Threads
      1. The Thread Class and the Runnable Interface
      2. Controlling Threads
      3. Death of a Thread
    2. Threading an Applet
      1. Issues Lurking
    3. Synchronization
      1. Serializing Access to Methods
      2. Accessing class and instance Variables from Multiple Threads
      3. The wait() and notify() Methods
      4. Passing Messages
      5. ThreadLocal Objects
    4. Scheduling and Priority
      1. Thread State
      2. Time-Slicing
      3. Priorities
      4. Yielding
    5. Thread Groups
      1. Working with ThreadGroups
      2. Uncaught Exceptions
    6. Thread Performance
      1. The Cost of Synchronization
      2. Thread Resource Consumption
    7. Concurrency Utilities
      1. Executors
      2. Locks
      3. Synchronization Constructs
      4. Atomic Operations
    8. Conclusion
  12. 10. Working with Text
    1. Text-Related APIs
    2. Strings
      1. Constructing Strings
      2. Strings from Things
      3. Comparing Strings
      4. Searching
      5. Editing
      6. String Method Summary
      7. StringBuilder and StringBuffer
    3. Internationalization
      1. The java.util.Locale Class
      2. Resource Bundles
    4. Parsing and Formatting Text
      1. Parsing Primitive Numbers
      2. Tokenizing Text
    5. Printf-Style Formatting
      1. Formatter
      2. The Format String
      3. String Conversions
      4. Primitive and Numeric Conversions
      5. Flags
      6. Miscellaneous
    6. Formatting with the java.text Package
      1. MessageFormat
    7. Regular Expressions
      1. Regex Notation
      2. The java.util.regex API
  13. 11. Core Utilities
    1. Math Utilities
      1. The java.lang.Math Class
      2. Big/Precise Numbers
      3. Floating-Point Components
      4. Random Numbers
    2. Dates and Times
      1. Working with Calendars
      2. Time Zones
      3. Parsing and Formatting with DateFormat
      4. Printf-Style Date and Time Formatting
    3. Timers
    4. Collections
      1. The Collection Interface
      2. Iterator
      3. Collection Types
      4. The Map Interface
      5. Collection Implementations
      6. Hash Codes and Key Values
      7. Synchronized and Unsynchronized Collections
      8. Read-Only and Read-Mostly Collections
      9. WeakHashMap
      10. EnumSet and EnumMap
      11. Sorting Collections
      12. A Thrilling Example
    5. Properties
      1. Loading and Storing
      2. System Properties
    6. The Preferences API
      1. Preferences for Classes
      2. Preferences Storage
      3. Change Notification
    7. The Logging API
      1. Overview
      2. Logging Levels
      3. A Simple Example
      4. Logging Setup Properties
      5. The Logger
      6. Performance
    8. Observers and Observables
  14. 12. Input/Output Facilities
    1. Streams
      1. Basic I/O
      2. Character Streams
      3. Stream Wrappers
      4. Pipes
      5. Streams from Strings and Back
      6. Implementing a Filter Stream
    2. File I/O
      1. The Class
      2. File Streams
      3. RandomAccessFile
      4. Resource Paths
    3. The NIO File API
      1. FileSystem and Path
      2. NIO File Operations
      3. Directory Operations
      4. Watching Paths
    4. Serialization
      1. Initialization with readObject()
      2. SerialVersionUID
    5. Data Compression
      1. Archives and Compressed Data
      2. Decompressing Data
      3. Zip Archive As a Filesystem
    6. The NIO Package
      1. Asynchronous I/O
      2. Performance
      3. Mapped and Locked Files
      4. Channels
      5. Buffers
      6. Character Encoders and Decoders
      7. FileChannel
      8. Scalable I/O with NIO
  15. 13. Network Programming
    1. Sockets
      1. Clients and Servers
      2. author="pat” timestamp="20120926T110720-0500” comment="one of those sections I hate to get rid of but is less relevant in terms of the example... should probably find a more modern example...”The DateAtHost Client
      3. The TinyHttpd Server
      4. Socket Options
      5. Proxies and Firewalls
    2. Datagram Sockets
      1. author="pat” timestamp="20120926T141346-0500” comment="I actually rewrote this as a standalone client but then decided to leave it as an applet”The HeartBeat Applet
      2. InetAddress
    3. Simple Serialized Object Protocols
      1. A Simple Object-Based Server
    4. Remote Method Invocation
      1. Real-World Usage
      2. Remote and Nonremote Objects
      3. An RMI Example
      4. RMI and CORBA
    5. Scalable I/O with NIO
      1. Selectable Channels
      2. Using Select
      3. LargerHttpd
      4. Nonblocking Client-Side Operations
  16. 14. Programming for the Web
    1. Uniform Resource Locators (URLs)
    2. The URL Class
      1. Stream Data
      2. Getting the Content as an Object
      3. Managing Connections
      4. Handlers in Practice
      5. Useful Handler Frameworks
    3. Talking to Web Applications
      1. Using the GET Method
      2. Using the POST Method
      3. The HttpURLConnection
      4. SSL and Secure Web Communications
      5. URLs, URNs, and URIs
    4. Web Services
      1. XML-RPC
      2. WSDL
      3. The Tools
      4. The Weather Service Client
  17. 15. Web Applications and Web Services
    1. Web Application Technologies
      1. Page-Oriented Versus “Single Page” Applications
      2. JSPs
      3. XML and XSL
      4. Web Application Frameworks
      5. Google Web Toolkit
      6. HTML5, AJAX, and More...
    2. Java Web Applications
      1. The Servlet Lifecycle
      2. Servlets
      3. The HelloClient Servlet
      4. The Servlet Response
      5. Servlet Parameters
      6. The ShowParameters Servlet
      7. User Session Management
      8. The ShowSession Servlet
      9. The ShoppingCart Servlet
      10. Cookies
      11. The ServletContext API
      12. Asynchronous Servlets
    3. WAR Files and Deployment
      1. Configuration with web.xml and Annotations
      2. URL Pattern Mappings
      3. Deploying HelloClient
      4. Error and Index Pages
      5. Security and Authentication
      6. Protecting Resources with Roles
      7. Secure Data Transport
      8. Authenticating Users
      9. Procedural Authorization
    4. Servlet Filters
      1. A Simple Filter
      2. A Test Servlet
      3. Declaring and Mapping Filters
      4. Filtering the Servlet Request
      5. Filtering the Servlet Response
    5. Building WAR Files with Ant
      1. A Development-Oriented Directory Layout
      2. Deploying and Redeploying WARs with Ant
    6. Implementing Web Services
      1. Defining the Service
      2. Our Echo Service
      3. Using the Service
      4. Data Types
    7. Conclusion
  18. 16. Swing
    1. Components
      1. Peers and Look-and-Feel
      2. The MVC Framework
      3. Painting
      4. Enabling and Disabling Components
      5. Focus, Please
      6. Other Component Methods
      7. Layout Managers
      8. Insets
      9. Z-Ordering (Stacking Components)
      10. The revalidate() and doLayout() Methods
      11. Managing Components
      12. Listening for Components
      13. Windows, Frames and Splash Screens
      14. Other Methods for Controlling Frames
      15. Content Panes
      16. Desktop Integration
    2. Events
      1. Event Receivers and Listener Interfaces
      2. Event Sources
      3. Event Delivery
      4. Event Types
      5. The java.awt.event.InputEvent Class
      6. Mouse and Key Modifiers on InputEvents
      7. Focus Events
    3. Event Summary
      1. Adapter Classes
      2. Dummy Adapters
    4. The AWT Robot!
    5. Multithreading in Swing
  19. 17. Using Swing Components
    1. Buttons and Labels
      1. HTML Text in Buttons and Labels
    2. Checkboxes and Radio Buttons
    3. Lists and Combo Boxes
    4. The Spinner
    5. Borders
    6. Menus
    7. Pop-Up Menus
      1. Component-Managed Pop Ups
    8. The JScrollPane Class
    9. The JSplitPane Class
    10. The JTabbedPane Class
    11. Scrollbars and Sliders
    12. Dialogs
      1. File Selection Dialog
      2. The Color Chooser
  20. 18. More Swing Components
    1. Text Components
      1. The TextEntryBox Application
      2. Formatted Text
      3. Filtering Input
      4. Validating Data
      5. Say the Magic Word
      6. Sharing a Data Model
      7. HTML and RTF for Free
      8. Managing Text Yourself
    2. Focus Navigation
      1. Trees
      2. Nodes and Models
      3. Save a Tree
      4. Tree Events
      5. A Complete Example
    3. Tables
      1. A First Stab: Freeloading
      2. Round Two: Creating a Table Model
      3. Round Three: A Simple Spreadsheet
      4. Sorting and Filtering
      5. Printing JTables
    4. Desktops
    5. Pluggable Look-and-Feel
    6. Creating Custom Components
      1. Generating Events
      2. A Dial Component
      3. Model and View Separation
  21. 19. Layout Managers
    1. FlowLayout
    2. GridLayout
    3. BorderLayout
    4. BoxLayout
    5. CardLayout
    6. GridBagLayout
      1. The GridBagConstraints Class
      2. Grid Coordinates
      3. The fill Constraint
      4. Spanning Rows and Columns
      5. Weighting
      6. Anchoring
      7. Padding and Insets
      8. Relative Positioning
      9. Composite Layouts
    7. Other Layout Managers
    8. Absolute Positioning
  22. 20. Drawing with the 2D API
    1. The Big Picture
    2. The Rendering Pipeline
    3. A Quick Tour of Java 2D
      1. Filling Shapes
      2. Drawing Shape Outlines
      3. Convenience Methods
      4. Drawing Text
      5. Drawing Images
      6. The Whole Iguana
    4. Filling Shapes
      1. Solid Colors
      2. Color Gradients
      3. Textures
      4. Desktop Colors
    5. Stroking Shape Outlines
    6. Using Fonts
      1. Font Metrics
    7. Displaying Images
      1. The Image Class
      2. Image Observers
      3. Scaling and Size
    8. Drawing Techniques
      1. Double Buffering
      2. Limiting Drawing with Clipping
      3. Offscreen Drawing
    9. Printing
  23. 21. Working with Images and Other Media
    1. Loading Images
      1. ImageObserver
      2. MediaTracker
      3. ImageIcon
      4. ImageIO
    2. Producing Image Data
      1. Drawing Animations
      2. BufferedImage Anatomy
      3. Color Models
      4. Creating an Image
      5. Updating a BufferedImage
    3. Filtering Image Data
      1. How ImageProcessor Works
      2. Converting an Image to a BufferedImage
      3. Using the RescaleOp Class
      4. Using the AffineTransformOp Class
    4. Saving Image Data
    5. Simple Audio
    6. Java Media Framework
  24. 22. JavaBeans
    1. What’s a Bean?
      1. What Constitutes a Bean?
    2. The NetBeans IDE
      1. Installing and Running NetBeans
    3. Properties and Customizers
    4. Event Hookups and Adapters
      1. Taming the Juggler
      2. Molecular Motion
    5. Binding Properties
      1. Constraining Properties
    6. Building Beans
      1. The Dial Bean
      2. Design Patterns for Properties
    7. Limitations of Visual Design
    8. Serialization Versus Code Generation
    9. Customizing with BeanInfo
      1. Getting Properties Information
    10. Handcoding with Beans
      1. Bean Instantiation and Type Management
      2. Working with Serialized Beans
      3. Runtime Event Hookups with Reflection
    11. BeanContext and BeanContextServices
    12. The Java Activation Framework
    13. Enterprise JavaBeans and POJO-Based Enterprise Frameworks
  25. 23. Applets
    1. The Politics of Browser-Based Applications
    2. Applet Support and the Java Plug-in
    3. The JApplet Class
      1. Applet Lifecycle
      2. The Applet Security Sandbox
      3. Getting Applet Resources
      4. The <applet> Tag
      5. Attributes
      6. Parameters
      7. ¿Habla Applet?
      8. The Complete <applet> Tag
      9. Loading Class Files
      10. Packages
      11. appletviewer
    4. Java Web Start
    5. Conclusion
  26. 24. XML
    1. The Butler Did It
    2. A Bit of Background
      1. Text Versus Binary
      2. A Universal Parser
      3. The State of XML
      4. The XML APIs
      5. XML and Web Browsers
    3. XML Basics
      1. Attributes
      2. XML Documents
      3. Encoding
      4. Namespaces
      5. Validation
      6. HTML to XHTML
    4. SAX
      1. The SAX API
      2. Building a Model Using SAX
      3. XMLEncoder/Decoder
    5. DOM
      1. The DOM API
      2. Test-Driving DOM
      3. Generating XML with DOM
      4. JDOM
    6. XPath
      1. Nodes
      2. Predicates
      3. Functions
      4. The XPath API
      5. XMLGrep
    7. XInclude
      1. Enabling XInclude
    8. Validating Documents
      1. Using Document Validation
      2. DTDs
      3. XML Schema
      4. The Validation API
    9. JAXB Code Binding and Generation
      1. Annotating Our Model
      2. Generating a Java Model from an XML Schema
      3. Generating an XML Schema from a Java Model
    10. Transforming Documents with XSL/XSLT
      1. XSL Basics
      2. Transforming the Zoo Inventory
      3. XSLTransform
      4. XSL in the Browser
    11. Web Services
    12. The End of the Book
  27. A. The Eclipse IDE
    1. The IDE Wars
    2. Getting Started with Eclipse
      1. Importing the Learning Java Examples
    3. Using Eclipse
      1. Getting at the Source
      2. The Lay of the Land
      3. Running the Examples
      4. Building the Ant-Based Examples
      5. Loner Examples
    4. Eclipse Features
      1. Coding Shortcuts
      2. Autocorrection
      3. Refactoring
      4. Diffing Files
      5. Organizing Imports
      6. Formatting Source Code
    5. Conclusion
  28. B. BeanShell: Java Scripting
    1. Running BeanShell
    2. Java Statements and Expressions
      1. Imports
    3. BeanShell Commands
    4. Scripted Methods and Objects
      1. Scripting Interfaces and Adapters
    5. Changing the Classpath
    6. Learning More . . .
  29. Glossary
  30. Index
  31. About the Authors
  32. Colophon
  33. Copyright
O'Reilly logo


Most fundamental I/O in Java is based on streams. A stream represents a flow of data with (at least conceptually) a writer at one end and a reader at the other. When you are working with the package to perform terminal input and output, reading or writing files, or communicating through sockets in Java, you are using various types of streams. Later in this chapter, we’ll look at the NIO package, which introduces a similar concept called a channel. One difference betwen the two is that streams are oriented around bytes or characters while channels are oriented around “buffers” containing those data types—yet they perform roughly the same job. Let’s start by summarizing the available types of streams:

InputStream, OutputStream

Abstract classes that define the basic functionality for reading or writing an unstructured sequence of bytes. All other byte streams in Java are built on top of the basic InputStream and OutputStream.

Reader, Writer

Abstract classes that define the basic functionality for reading or writing a sequence of character data, with support for Unicode. All other character streams in Java are built on top of Reader and Writer.

InputStreamReader, OutputStreamWriter

Classes that bridge byte and character streams by converting according to a specific character encoding scheme. (Remember: in Unicode, a character is not a byte!)

DataInputStream, DataOutputStream

Specialized stream filters that add the ability to read and write multibyte data types, such as numeric primitives and String objects in a universal format.

ObjectInputStream, ObjectOutputStream

Specialized stream filters that are capable of writing whole groups of serialized Java objects and reconstructing them.

BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter

Specialized stream filters that add buffering for additional efficiency. For real-world I/O, a buffer is almost always used.

PrintStream, PrintWriter

Specialized streams that simplify printing text.

PipedInputStream, PipedOutputStream, PipedReader, PipedWriter

“Loopback” streams that can be used in pairs to move data within an application. Data written into a PipedOutputStream or PipedWriter is read from its corresponding PipedInputStream or PipedReader.

FileInputStream, FileOutputStream, FileReader, FileWriter

Implementations of InputStream, OutputStream, Reader, and Writer that read from and write to files on the local filesystem.

author="pat” timestamp="20121117T215954-0600” comment="I think this originally came from the nutshell book. Do they have an update for this diagram that we could use? (Maybe one for NIO?)”The package

Figure 12-1. The package

Streams in Java are one-way streets. The input and output classes represent the ends of a simple stream, as shown in Figure 12-2. For bidirectional conversations, you’ll use one of each type of stream.

Basic input and output stream functionality

Figure 12-2. Basic input and output stream functionality

InputStream and OutputStream are abstract classes that define the lowest-level interface for all byte streams. They contain methods for reading or writing an unstructured flow of byte-level data. Because these classes are abstract, you can’t create a generic input or output stream. Java implements subclasses of these for activities such as reading from and writing to files and communicating with sockets. Because all byte streams inherit the structure of InputStream or OutputStream, the various kinds of byte streams can be used interchangeably. A method specifying an InputStream as an argument can accept any subclass of InputStream. Specialized types of streams can also be layered or wrapped around basic streams to add features such as buffering, filtering, or handling higher-level data types.

Reader and Writer are very much like InputStream and OutputStream, except that they deal with characters instead of bytes. As true character streams, these classes correctly handle Unicode characters, which is not always the case with byte streams. Often, a bridge is needed between these character streams and the byte streams of physical devices, such as disks and networks. InputStreamReader and OutputStreamWriter are special classes that use a character-encoding scheme to translate between character and byte streams.

This section describes all the interesting stream types with the exception of FileInputStream, FileOutputStream, FileReader, and FileWriter. We postpone the discussion of file streams until the next section, where we cover issues involved with accessing the filesystem in Java.

Basic I/O

The prototypical example of an InputStream object is the standard input of a Java application. Like stdin in C or cin in C++, this is the source of input to a command-line (non-GUI) program. It is an input stream from the environment—usually a terminal window or possibly the output of another command. The java.lang.System class, a general repository for system-related resources, provides a reference to the standard input stream in the static variable It also provides a standard output stream and a standard error stream in the out and err variables, respectively.[34] The following example shows the correspondence:

    InputStream stdin =;
    OutputStream stdout = System.out;
    OutputStream stderr = System.err;

This snippet hides the fact that System.out and System.err aren’t just OutputStream objects, but more specialized and useful PrintStream objects. We’ll explain these later, but for now we can reference out and err as OutputStream objects because they are derived from OutputStream.

We can read a single byte at a time from standard input with the InputStream’s read() method. If you look closely at the API, you’ll see that the read() method of the base InputStream class is an abstract method. What lies behind is a particular implementation of InputStream that provides the real implementation of the read() method:

    try {
        int val =;
    } catch ( IOException e ) {

Although we said that the read() method reads a byte value, the return type in the example is int, not byte. That’s because the read() method of basic input streams in Java uses a convention carried over from the C language to indicate the end of a stream with a special value. Data byte values are returned as unsigned integers in the range 0 to 255 and the special value of -1 is used to indicate that end of stream has been reached. You’ll need to test for this condition when using the simple read() method. You can then cast the value to a byte if needed. The following example reads each byte from an input stream and prints its value:

    try {
        int val;
        while( ( != -1 )
    } catch ( IOException e ) { ... }

As we’ve shown in the examples, the read() method can also throw an IOException if there is an error reading from the underlying stream source. Various subclasses of IOException may indicate that a source such as a file or network connection has had an error. Additionally, higher-level streams that read data types more complex than a single byte may throw EOFException (“end of file”), which indicates an unexpected or premature end of stream.

An overloaded form of read() fills a byte array with as much data as possible up to the capacity of the array and returns the number of bytes read:

    byte [] buff = new byte [1024];
    int got = buff );

In theory, we can also check the number of bytes available for reading at a given time on an InputStream using the available() method. With that information, we could create an array of exactly the right size:

    int waiting =;
    if ( waiting > 0 ) {
        byte [] data = new byte [ waiting ]; data );

However, the reliability of this technique depends on the ability of the underlying stream implementation to detect how much data can be retrieved. It generally works for files but should not be relied upon for all types of streams.

These read() methods block until at least some data is read (at least one byte). You must, in general, check the returned value to determine how much data you got and if you need to read more. (We look at nonblocking I/O later in this chapter.) The skip() method of InputStream provides a way of jumping over a number of bytes. Depending on the implementation of the stream, skipping bytes may be more efficient than reading them.

The close() method shuts down the stream and frees up any associated system resources. It’s important for performance to remember to close most types of streams when you are finished using them. In some cases, streams may be closed automatically when objects are garbage-collected, but it is not a good idea to rely on this behavior. In Java 7, the try-with-resources language feature was added to make automatically closing streams and other closeable entities easier. We’ll see some examples of that later in this chapter. The flag interface identifies all types of stream, channel, and related utility classes that can be closed.

Finally, we should mention that in addition to the and System.out standard streams, Java provides the API through System.console(). You can use the Console to read passwords without echoing them to the screen.

Character Streams

In early versions of Java, some InputStream and OutputStream types included methods for reading and writing strings, but most of them operated by naively assuming that a 16-bit Unicode character was equivalent to an 8-bit byte in the stream. This works only for Latin-1 (ISO 8859-1) characters and not for the world of other encodings that are used with different languages. In Chapter 10, we saw that the java.lang.String class has a byte array constructor and a corresponding getBytes() method that each accept character encoding as an argument. In theory, we could use these as tools to transform arrays of bytes to and from Unicode characters so that we could work with byte streams that represent character data in any encoding format. Fortunately, however, we don’t have to rely on this because Java has streams that handle this for us.

The Reader and Writer character stream classes were introduced as streams that handle character data only. When you use these classes, you think only in terms of characters and string data and allow the underlying implementation to handle the conversion of bytes to a specific character encoding. As we’ll see, some direct implementations of Reader and Writer exist, for example, for reading and writing files. But more generally, two special classes, InputStreamReader and OutputStreamWriter, bridge the gap between the world of character streams and the world of byte streams. These are, respectively, a Reader and a Writer that can be wrapped around any underlying byte stream to make it a character stream. An encoding scheme is used to convert between possible multibyte encoded values and Java Unicode characters. An encoding scheme can be specified by name in the constructor of InputStreamReader or OutputStreamWriter. For convenience, the default constructor uses the system’s default encoding scheme.

For example, let’s parse a human-readable string from the standard input into an integer. We’ll assume that the bytes coming from use the system’s default encoding scheme:

    try {
        InputStream in =;
        InputStreamReader charsIn = new InputStreamReader( in );
        BufferedReader bufferedCharsIn = new BufferedReader( inReader );

        String line = bufferedCharsIn.readLine();
        int i = NumberFormat.getInstance().parse( line ).intValue();
    } catch ( IOException e ) {
    } catch ( ParseException pe ) { }

First, we wrap an InputStreamReader around This reader converts the incoming bytes of to characters using the default encoding scheme. Then, we wrap a BufferedReader around the InputStreamReader. BufferedReader adds the readLine() method, which we can use to grab a full line of text (up to a platform-specific, line-terminator character combination) into a String. The string is then parsed into an integer using the techniques described in Chapter 10.

The important thing to note is that we have taken a byte-oriented input stream,, and safely converted it to a Reader for reading characters. If we wished to use an encoding other than the system default, we could have specified it in the InputStreamReader’s constructor like so:

    InputStreamReader reader = new InputStreamReader(, "UTF-8" );

For each character that is read from the reader, the InputStreamReader reads one or more bytes and performs the necessary conversion to Unicode.

In Chapter 13, we use an InputStreamReader and a Writer in our simple web server example, where we must use a character encoding specified by the HTTP protocol. We also return to the topic of character encodings when we discuss the java.nio.charset API, which allows you to query for and use encoders and decoders explicitly on buffers of characters and bytes. Both InputStreamReader and OutputStreamWriter can accept a Charset codec object as well as a character encoding name.

Stream Wrappers

What if we want to do more than read and write a sequence of bytes or characters? We can use a “filter” stream, which is a type of InputStream, OutputStream, Reader, or Writer that wraps another stream and adds new features. A filter stream takes the target stream as an argument in its constructor and delegates calls to it after doing some additional processing of its own. For example, we can construct a BufferedInputStream to wrap the system standard input:

    InputStream bufferedIn = new BufferedInputStream( );

The BufferedInputStream is a type of filter stream that reads ahead and buffers a certain amount of data. (We’ll talk more about it later in this chapter.) The BufferedInputStream wraps an additional layer of functionality around the underlying stream. Figure 12-3 shows this arrangement for a DataInputStream, which is a type of stream that can read higher-level data types, such as Java primitives and strings.

Layered streams

Figure 12-3. Layered streams

As you can see from the previous code snippet, the BufferedInputStream filter is a type of InputStream. Because filter streams are themselves subclasses of the basic stream types, they can be used as arguments to the construction of other filter streams. This allows filter streams to be layered on top of one another to provide different combinations of features. For example, we could first wrap our with a BufferedInputStream and then wrap the BufferedInputStream with a DataInputStream for reading special data types with buffering.

Java provides base classes for creating new types of filter streams: FilterInputStream, FilterOutputStream, FilterReader, and FilterWriter. These superclasses provide the basic machinery for a “no op” filter (a filter that doesn’t do anything) by delegating all their method calls to their underlying stream. Real filter streams subclass these and override various methods to add their additional processing. We’ll make an example filter stream later in this chapter.

Data streams

DataInputStream and DataOutputStream are filter streams that let you read or write strings and primitive data types composed of more than a single byte. DataInputStream and DataOutputStream implement the DataInput and DataOutput interfaces, respectively. These interfaces define methods for reading or writing strings and all of the Java primitive types, including numbers and Boolean values. DataOutputStream encodes these values in a machine-independent manner and then writes them to its underlying byte stream. DataInputStream does the converse.

You can construct a DataInputStream from an InputStream and then use a method such as readDouble() to read a primitive data type:

    DataInputStream dis = new DataInputStream( );
    double d = dis.readDouble();

This example wraps the standard input stream in a DataInputStream and uses it to read a double value. The readDouble() method reads bytes from the stream and constructs a double from them. The DataInputStream methods expect the bytes of numeric data types to be in network byte order, a standard that specifies that the high-order bytes are sent first (also known as “big endian,” as we discuss later).

The DataOutputStream class provides write methods that correspond to the read methods in DataInputStream. For example, writeInt() writes an integer in binary format to the underlying output stream.

The readUTF() and writeUTF() methods of DataInputStream and DataOutputStream read and write a Java String of Unicode characters using the UTF-8 “transformation format” character encoding. UTF-8 is an ASCII-compatible encoding of Unicode characters that is very widely used. Not all encodings are guaranteed to preserve all Unicode characters, but UTF-8 does. You can also use UTF-8 with Reader and Writer streams by specifying it as the encoding name.

Buffered streams

The BufferedInputStream, BufferedOutputStream, BufferedReader, and BufferedWriter classes add a data buffer of a specified size to the stream path. A buffer can increase efficiency by reducing the number of physical read or write operations that correspond to read() or write() method calls. You create a buffered stream with an appropriate input or output stream and a buffer size. (You can also wrap another stream around a buffered stream so that it benefits from the buffering.) Here’s a simple buffered input stream called bis:

    BufferedInputStream bis = new BufferedInputStream(myInputStream, 32768);

In this example, we specify a buffer size of 32 KB. If we leave off the size of the buffer in the constructor, a reasonably sized one is chosen for us. (Currently the default is 8 KB.) On our first call to read(), bis tries to fill our entire 32 KB buffer with data, if it’s available. Thereafter, calls to read() retrieve data from the buffer, which is refilled as necessary.

A BufferedOutputStream works in a similar way. Calls to write() store the data in a buffer; data is actually written only when the buffer fills up. You can also use the flush() method to wring out the contents of a BufferedOutputStream at any time. The flush() method is actually a method of the OutputStream class itself. It’s important because it allows you to be sure that all data in any underlying streams and filter streams has been sent (before, for example, you wait for a response).

Some input streams such as BufferedInputStream support the ability to mark a location in the data and later reset the stream to that position. The mark() method sets the return point in the stream. It takes an integer value that specifies the number of bytes that can be read before the stream gives up and forgets about the mark. The reset() method returns the stream to the marked point; any data read after the call to mark() is read again.

This functionality could be useful when you are reading the stream in a parser. You may occasionally fail to parse a structure and so must try something else. In this situation, you can have your parser generate an error and then reset the stream to the point before it began parsing the structure:

    BufferedInputStream input;
    try {
        input.mark( MAX_DATA_STRUCTURE_SIZE );
        return( parseDataStructure( input ) );
    catch ( ParseException e ) {

The BufferedReader and BufferedWriter classes work just like their byte-based counterparts, except that they operate on characters instead of bytes.

PrintWriter and PrintStream

Another useful wrapper stream is This class provides a suite of overloaded print() methods that turn their arguments into strings and push them out the stream. A complementary set of println() convenience methods appends a new line to the end of the strings. For formatted text output, printf() and the identical format() methods allow you to write printf-style formatted text to the stream.

PrintWriter is an unusual character stream because it can wrap either an OutputStream or another Writer. PrintWriter is the more capable big brother of the legacy PrintStream byte stream. The System.out and System.err streams are PrintStream objects; you have already seen such streams strewn throughout this book:

    System.out.print("Hello, world...\n");
    System.out.println("Hello, world...");
    System.out.printf("The answer is %d", 17 );
    System.out.println( 3.14 );

Early versions of Java did not have the Reader and Writer classes and used PrintStream, which convert bytes to characters by simply made assumptions about the character encoding. You should use a PrintWriter for all new development.

When you create a PrintWriter object, you can pass an additional Boolean value to the constructor, specifying whether it should “auto-flush.” If this value is true, the PrintWriter automatically performs a flush() on the underlying OutputStream or Writer each time it sends a newline:

PrintWriter pw = new PrintWriter( myOutputStream, true /*autoFlush*/ );
    pw.println("Hello!"); // Stream is automatically flushed by the newline.

When this technique is used with a buffered output stream, it corresponds to the behavior of terminals that send data line by line.

The other big advantage that print streams have over regular character streams is that they shield you from exceptions thrown by the underlying streams. Unlike methods in other stream classes, the methods of PrintWriter and PrintStream do not throw IOExceptions. Instead, they provide a method to explicitly check for errors if required. This makes life a lot easier for printing text, which is a very common operation. You can check for errors with the checkError() method:

    System.out.println( reallyLongString );
    if ( System.out.checkError() ){ ...  // uh oh


Normally, our applications are directly involved with one side of a given stream at a time. PipedInputStream and PipedOutputStream (or PipedReader and PipedWriter), however, let us create two sides of a stream and connect them, as shown in Figure 12-4. This can be used to provide a stream of communication between threads, for example, or as a “loopback” for testing. Often it’s used as a crutch to interface a stream-oriented API to a non-stream-oriented API.

Piped streams

Figure 12-4. Piped streams

To create a bytestream pipe, we use both a PipedInputStream and a PipedOutputStream. We can simply choose a side and then construct the other side using the first as an argument:

    PipedInputStream pin = new PipedInputStream();
    PipedOutputStream pout = new PipedOutputStream( pin );


    PipedOutputStream pout = new PipedOutputStream();
    PipedInputStream pin = new PipedInputStream( pout );

In each of these examples, the effect is to produce an input stream, pin, and an output stream, pout, that are connected. Data written to pout can then be read by pin. It is also possible to create the PipedInputStream and the PipedOutputStream separately and then connect them with the connect() method.

We can do exactly the same thing in the character-based world, using PipedReader and PipedWriter in place of PipedInputStream and PipedOutputStream.

After the two ends of the pipe are connected, use the two streams as you would other input and output streams. You can use read() to read data from the PipedInputStream (or PipedReader) and write() to write data to the PipedOutputStream (or PipedWriter). If the internal buffer of the pipe fills up, the writer blocks and waits until space is available. Conversely, if the pipe is empty, the reader blocks and waits until some data is available.

One advantage to using piped streams is that they provide stream functionality in our code without compelling us to build new, specialized streams. For example, we can use pipes to create a simple logging or “console” facility for our application. We can send messages to the logging facility through an ordinary PrintWriter, and then it can do whatever processing or buffering is required before sending the messages off to their ultimate destination. Because we are dealing with string messages, we use the character-based PipedReader and PipedWriter classes. The following example shows the skeleton of our logging facility:

    class LoggerDaemon extends Thread
        PipedReader in = new PipedReader();

        LoggerDaemon() {

        public void run() {
            BufferedReader bin = new BufferedReader( in );
            String s;
            try {
               while ( (s = bin.readLine()) != null ) {
                    // process line of data
            } catch (IOException e ) { }

        PrintWriter getWriter() throws IOException {
            return new PrintWriter( new PipedWriter( in ) );

    class myApplication {
        public static void main ( String [] args ) throws IOException {
            PrintWriter out = new LoggerDaemon().getWriter();

            out.println("Application starting...");
            // ...
            out.println("Warning: does not compute!");
            // ...

LoggerDaemon reads strings from its end of the pipe, the PipedReader named in. LoggerDaemon also provides a method, getWriter(), which returns a PipedWriter that is connected to its input stream. To begin sending messages, we create a new LoggerDaemon and fetch the output stream. In order to read strings with the readLine() method, LoggerDaemon wraps a BufferedReader around its PipedReader. For convenience, it also presents its output pipe as a PrintWriter rather than a simple Writer.

One advantage of implementing LoggerDaemon with pipes is that we can log messages as easily as we write text to a terminal or any other stream. In other words, we can use all our normal tools and techniques, including printf(). Another advantage is that the processing happens in another thread, so we can go about our business while any processing takes place.

Streams from Strings and Back

StringReader is another useful stream class; it essentially wraps stream functionality around a String. Here’s how to use a StringReader:

    String data = "There once was a man from Nantucket...";
    StringReader sr = new StringReader( data );

    char T = (char);
    char h = (char);
    char e = (char);

Note that you will still have to catch IOExceptions that are thrown by some of the StringReader’s methods.

The StringReader class is useful when you want to read data from a String as if it were coming from a stream, such as a file, pipe, or socket. Suppose you create a parser that expects to read from a stream, but you want to provide an alternative method that also parses a big string. You can easily add one using StringReader.

Turning things around, the StringWriter class lets us write to a character buffer via an output stream. The internal buffer grows as necessary to accommodate the data. When we are done, we can fetch the contents of the buffer as a String. In the following example, we create a StringWriter and wrap it in a PrintWriter for convenience:

    StringWriter buffer = new StringWriter();
    PrintWriter out = new PrintWriter( buffer );

    out.println("A moose once bit my sister.");
    out.println("No, really!");

    String results = buffer.toString();

First, we print a few lines to the output stream to give it some data and then retrieve the results as a string with the toString() method. Alternately, we could get the results as a StringBuffer object using the getBuffer() method.

The StringWriter class is useful if you want to capture the output of something that normally sends output to a stream, such as a file or the console. A PrintWriter wrapped around a StringWriter is a viable alternative to using a StringBuffer to construct large strings piece by piece.

The ByteArrayInputStream and ByteArrayOutputStream work with bytes in the same way the previous examples worked with characters. You can write byte data to a ByteArrayOutputStream and retrieve it later with the toByteArray() method. Conversely, you can construct a ByteArrayInputStream from a byte array as StringReader does with a String. For example, if we want to see exactly what our DataOutputStream is writing when we tell it to encode a particular value, we could capture it with a byte array output stream:

    ByteArrayOutputStream bao = new ByteArrayOutputStream();
    DataOutputStream dao = new DataOutputStream( bao );
    dao.writeInt( 16777216 );
    byte [] bytes = bao.toByteArray();
    for( byte b : bytes )
        System.out.println( b );  // 1, 0, 0, 0

Implementing a Filter Stream

Before we leave streams, let’s try making one of our own. We mentioned earlier that specialized stream wrappers are built on top of the FilterInputStream and FilterOutputStream classes. It’s quite easy to create our own subclass of FilterInputStream that can be wrapped around other streams to add new functionality.

The following example, rot13InputStream, performs a rot13 (rotate by 13 letters) operation on the bytes that it reads. rot13 is a trivial obfuscation algorithm that shifts alphabetic characters to make them not quite human-readable (it simply passes over nonalphabetic characters without modifying them). rot13 is cute because it’s symmetric: to “un-rot13” some text, you simply rot13 it again. Here’s our rot13InputStream class:

    public class rot13InputStream extends FilterInputStream
        public rot13InputStream ( InputStream i ) {
            super( i );

        public int read() throws IOException {
            return rot13( );
        // should override additional read() methods
        private int rot13 ( int c ) {
            if ( (c >= 'A') && (c <= 'Z') )
            if ( (c >= 'a') && (c <= 'z') )
            return c;

The FilterInputStream needs to be initialized with an InputStream; this is the stream to be filtered. We provide an appropriate constructor for the rot13InputStream class and invoke the parent constructor with a call to super(). FilterInputStream contains a protected instance variable, in, in which it stores a reference to the specified InputStream, making it available to the rest of our class.

The primary feature of a FilterInputStream is that it delegates its input tasks to the underlying InputStream. For instance, a call to FilterInputStream’s read() method simply turns around and calls the read() method of the underlying InputStream to fetch a byte. The filtering happens when we do our extra work on the data as it passes through. In our example, the read() method fetches a byte from the underlying InputStream, in, and then performs the rot13 shift on the byte before returning it. The rot13() method shifts alphabetic characters while simply passing over all other values, including the end-of-stream value (-1). Our subclass is now a rot13 filter.

read() is the only InputStream method that FilterInputStream overrides. All other normal functionality of an InputStream, such as skip() and available(), is unmodified, so calls to these methods are answered by the underlying InputStream.

Strictly speaking, rot13InputStream works only on an ASCII byte stream because the underlying algorithm is based on the Roman alphabet. A more generalized character-scrambling algorithm would have to be based on FilterReader to handle 16-bit Unicode classes correctly. (Anyone want to try rot32768?) We should also note that we have not fully implemented our filter: we should also override the version of read() that takes a byte array and range specifiers, perhaps delegating it to our own read. Unless we do so, a reader using that method would get the raw stream.

[34] Standard error is a stream that is usually reserved for error-related text messages that should be shown to the user of a command-line application. It is differentiated from the standard output, which often might be redirected to a file or another application and not seen by the user.

The best content for your career. Discover unlimited learning on demand for around $1/day.