SlideShare a Scribd company logo
Core Java Vol Iiadvanced Features 12th Edition
Cay S Horstmann download
https://ebookbell.com/product/core-java-vol-iiadvanced-
features-12th-edition-cay-s-horstmann-49554648
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann
https://ebookbell.com/product/core-java-vol-iiadvanced-features-12th-
edition-cay-s-horstmann-38321494
Core Java Volume Ii Advanced Features 11th Vol Ii Cay Horstmann
https://ebookbell.com/product/core-java-volume-ii-advanced-
features-11th-vol-ii-cay-horstmann-9992752
Core Java Vol 1 2 For The Impatient And Effective Pack 12th Ed Cay S
Horstmann
https://ebookbell.com/product/core-java-vol-1-2-for-the-impatient-and-
effective-pack-12th-ed-cay-s-horstmann-50687482
Core Java Volume I Fundamentals 12th Horstmann Cay
https://ebookbell.com/product/core-java-volume-i-fundamentals-12th-
horstmann-cay-46173296
Core Java Volume Ii Advanced Features 12th Cay S Horstmann
https://ebookbell.com/product/core-java-volume-ii-advanced-
features-12th-cay-s-horstmann-46173298
Core Java For The Impatient 3rd Edition Cay Horstmann
https://ebookbell.com/product/core-java-for-the-impatient-3rd-edition-
cay-horstmann-48456364
Core Java Interview Questions Youll Most Likely Be Asked Job Interview
Questions Series 2nd Edition Vibrant Publishers
https://ebookbell.com/product/core-java-interview-questions-youll-
most-likely-be-asked-job-interview-questions-series-2nd-edition-
vibrant-publishers-49183978
Core Java Made Simple Som Prakash Rai
https://ebookbell.com/product/core-java-made-simple-som-prakash-
rai-49422914
Core Java Volume Ifundamentals Cay S Horstmann
https://ebookbell.com/product/core-java-volume-ifundamentals-cay-s-
horstmann-49541448
Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann
Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann
Core Java, Vol. II-Advanced
Features
12th Edition
Cay S. Horstmann
Contents
Preface
Acknowledgments
Chapter 1: Streams
Chapter 2: Input and Output
Chapter 3: XML
Chapter 4: Networking
Chapter 5: Database Programming
Chapter 6: The Date and Time API
Chapter 7: Internationalization
Chapter 8: Scripting, Compiling, and Annotation Processing
Chapter 9: The Java Platform Module System
Chapter 10: Security
Chapter 11: Advanced Swing and Graphics
Chapter 12: Native Methods
Table of Contents
Preface
Acknowledgments
Chapter 1: Streams
1.1 From Iterating to Stream Operations
1.2 Stream Creation
1.3 The filter, map, and flatMap Methods
1.4 Extracting Substreams and Combining Streams
1.5 Other Stream Transformations
1.6 Simple Reductions
1.7 The Optional Type
1.7.1 Getting an Optional Value
1.7.2 Consuming an Optional Value
1.7.3 Pipelining Optional Values
1.7.4 How Not to Work with Optional Values
1.7.5 Creating Optional Values
1.7.6 Composing Optional Value Functions with flatMap
1.7.7 Turning an Optional into a Stream
1.8 Collecting Results
1.9 Collecting into Maps
1.10 Grouping and Partitioning
1.11 Downstream Collectors
1.12 Reduction Operations
1.13 Primitive Type Streams
1.14 Parallel Streams
Chapter 2: Input and Output
2.1 Input/Output Streams
2.1.1 Reading and Writing Bytes
2.1.2 The Complete Stream Zoo
2.1.3 Combining Input/Output Stream Filters
2.1.4 Text Input and Output
2.1.5 How to Write Text Output
2.1.6 How to Read Text Input
2.1.7 Saving Objects in Text Format
2.1.8 Character Encodings
2.2 Reading and Writing Binary Data
2.2.1 The DataInput and DataOutput interfaces
2.2.2 Random-Access Files
2.2.3 ZIP Archives
2.3 Object Input/Output Streams and Serialization
2.3.1 Saving and Loading Serializable Objects
2.3.2 Understanding the Object Serialization File Format
2.3.3 Modifying the Default Serialization Mechanism
2.3.4 The readResolve and writeReplace methods
2.3.5 Versioning
2.3.6 Using Serialization for Cloning
2.3.7 Deserialization and Security
2.4 Working with Files
2.4.1 Paths
2.4.2 Reading and Writing Files
2.4.3 Creating Files and Directories
2.4.4 Copying, Moving, and Deleting Files
2.4.5 Getting File Information
2.4.6 Visiting Directory Entries
2.4.7 Using Directory Streams
2.4.8 ZIP File Systems
2.5 Memory-Mapped Files
2.5.1 Memory-Mapped File Performance
2.5.2 The Buffer Data Structure
2.6 File Locking
2.7 Regular Expressions
2.7.1 The Regular Expression Syntax
2.7.2 Matching an Entire String
2.7.3 Finding All Matches in a String
2.7.4 Groups
2.7.5 Splitting along Delimiters
2.7.6 Replacing Matches
2.7.7 Flags
Chapter 3: XML
3.1 Introducing XML
3.2 The Structure of an XML Document
3.3 Parsing an XML Document
3.4 Validating XML Documents
3.4.1 Document Type Definitions
3.4.2 XML Schema
3.4.3 A Practical Example
3.5 Locating Information with XPath
3.6 Using Namespaces
3.7 Streaming Parsers
3.7.1 Using the SAX Parser
3.7.2 Using the StAX Parser
3.8 Generating XML Documents
3.8.1 Documents without Namespaces
3.8.2 Documents with Namespaces
3.8.3 Writing Documents
3.8.4 Writing an XML Document with StAX
3.8.5 An Example: Generating an SVG File
3.9 XSL Transformations
Chapter 4: Networking
4.1 Connecting to a Server
4.1.1 Using Telnet
4.1.2 Connecting to a Server with Java
4.1.3 Socket Timeouts
4.1.4 Internet Addresses
4.2 Implementing Servers
4.2.1 Server Sockets
4.2.2 Serving Multiple Clients
4.2.3 Half-Close
4.2.4 Interruptible Sockets
4.3 Getting Web Data
4.3.1 URLs and URIs
4.3.2 Using a URLConnection to Retrieve Information
4.3.3 Posting Form Data
4.4 The HTTP Client
4.4.1 The HttpClient Class
4.4.2 The HttpRequest class and Body Publishers
4.4.3 The HttpResponse Interface and Body Handlers
4.4.4 Asynchronous Processing
4.5 Sending E-Mail
Chapter 5: Database Programming
5.1 The Design of JDBC
5.1.1 JDBC Driver Types
5.1.2 Typical Uses of JDBC
5.2 The Structured Query Language
5.3 JDBC Configuration
5.3.1 Database URLs
5.3.2 Driver JAR Files
5.3.3 Starting the Database
5.3.4 Registering the Driver Class
5.3.5 Connecting to the Database
5.4 Working with JDBC Statements
5.4.1 Executing SQL Statements
5.4.2 Managing Connections, Statements, and Result Sets
5.4.3 Analyzing SQL Exceptions
5.4.4 Populating a Database
5.5 Query Execution
5.5.1 Prepared Statements
5.5.2 Reading and Writing LOBs
5.5.3 SQL Escapes
5.5.4 Multiple Results
5.5.5 Retrieving Autogenerated Keys
5.6 Scrollable and Updatable Result Sets
5.6.1 Scrollable Result Sets
5.6.2 Updatable Result Sets
5.7 Row Sets
5.7.1 Constructing Row Sets
5.7.2 Cached Row Sets
5.8 Metadata
5.9 Transactions
5.9.1 Programming Transactions with JDBC
5.9.2 Save Points
5.9.3 Batch Updates
5.9.4 Advanced SQL Types
5.10 Connection Management in Web and Enterprise Applications
Chapter 6: The Date and Time API
6.1 The Time Line
6.2 Local Dates
6.3 Date Adjusters
6.4 Local Time
6.5 Zoned Time
6.6 Formatting and Parsing
6.7 Interoperating with Legacy Code
Chapter 7: Internationalization
7.1 Locales
7.1.1 Why Locales?
7.1.2 Specifying Locales
7.1.3 The Default Locale
7.1.4 Display Names
7.2 Number Formats
7.2.1 Formatting Numeric Values
7.2.2 The DecimalFormat Class
7.2.3 Currencies
7.3 Date and Time
7.4 Collation and Normalization
7.5 Message Formatting
7.5.1 Formatting Numbers and Dates
7.5.2 Choice Formats
7.6 Text Input and Output
7.6.1 Text Files
7.6.2 Line Endings
7.6.3 The Console
7.6.4 Log Files
7.6.5 The UTF-8 Byte Order Mark
7.6.6 Character Encoding of Source Files
7.7 Resource Bundles
7.7.1 Locating Resource Bundles
7.7.2 Property Files
7.7.3 Bundle Classes
7.8 A Complete Example
Chapter 8: Scripting, Compiling, and Annotation Processing
8.1 Scripting for the Java Platform
8.1.1 Getting a Scripting Engine
8.1.2 Script Evaluation and Bindings
8.1.3 Redirecting Input and Output
8.1.4 Calling Scripting Functions and Methods
8.1.5 Compiling a Script
8.1.6 An Example: Scripting GUI Events
8.2 The Compiler API
8.2.1 Invoking the Compiler
8.2.2 Launching a Compilation Task
8.2.3 Capturing Diagnostics
8.2.4 Reading Source Files from Memory
8.2.5 Writing Byte Codes to Memory
8.2.6 An Example: Dynamic Java Code Generation
8.3 Using Annotations
8.3.1 An Introduction into Annotations
8.3.2 An Example: Annotating Event Handlers
8.4 Annotation Syntax
8.4.1 Annotation Interfaces
8.4.2 Annotations
8.4.3 Annotating Declarations
8.4.4 Annotating Type Uses
8.4.5 Annotating this
8.5 Standard Annotations
8.5.1 Annotations for Compilation
8.5.2 Meta-Annotations
8.6 Source-Level Annotation Processing
8.6.1 Annotation Processors
8.6.2 The Language Model API
8.6.3 Using Annotations to Generate Source Code
8.7 Bytecode Engineering
8.7.1 Modifying Class Files
8.7.2 Modifying Bytecodes at Load Time
Chapter 9: The Java Platform Module System
9.1 The Module Concept
9.2 Naming Modules
9.3 The Modular “Hello, World!” Program
9.4 Requiring Modules
9.5 Exporting Packages
9.6 Modular JARs
9.7 Modules and Reflective Access
9.8 Automatic Modules
9.9 The Unnamed Module
9.10 Command-Line Flags for Migration
9.11 Transitive and Static Requirements
9.12 Qualified Exporting and Opening
9.13 Service Loading
9.14 Tools for Working with Modules
Chapter 10: Security
10.1 Class Loaders
10.1.1 The Class-Loading Process
10.1.2 The Class Loader Hierarchy
10.1.3 Using Class Loaders as Namespaces
10.1.4 Writing Your Own Class Loader
10.1.5 Bytecode Verification
10.2 User Authentication
10.2.1 The JAAS Framework
10.2.2 JAAS Login Modules
10.3 Digital Signatures
10.3.1 Message Digests
10.3.2 Message Signing
10.3.3 Verifying a Signature
10.3.4 The Authentication Problem
10.3.5 Certificate Signing
10.3.6 Certificate Requests
10.3.7 Code Signing
10.4 Encryption
10.4.1 Symmetric Ciphers
10.4.2 Key Generation
10.4.3 Cipher Streams
10.4.4 Public Key Ciphers
Chapter 11: Advanced Swing and Graphics
11.1 Tables
11.1.1 A Simple Table
11.1.2 Table Models
11.1.3 Working with Rows and Columns
11.1.3.1 Column Classes
11.1.3.2 Accessing Table Columns
11.1.3.3 Resizing Columns
11.1.3.4 Resizing Rows
11.1.3.5 Selecting Rows, Columns, and Cells
11.1.3.6 Sorting Rows
11.1.3.7 Filtering Rows
11.1.3.8 Hiding and Displaying Columns
11.1.4 Cell Rendering and Editing
11.1.4.1 Rendering Cells
11.1.4.2 Rendering the Header
11.1.4.3 Editing Cells
11.1.4.4 Custom Editors
11.2 Trees
11.2.1 Simple Trees
11.2.1.1 Editing Trees and Tree Paths
11.2.2 Node Enumeration
11.2.3 Rendering Nodes
11.2.4 Listening to Tree Events
11.2.5 Custom Tree Models
11.3 Advanced AWT
11.3.1 The Rendering Pipeline
11.3.2 Shapes
11.3.2.1 The Shape Class Hierarchy
11.3.2.2 Using the Shape Classes
11.3.3 Areas
11.3.4 Strokes
11.3.5 Paint
11.3.6 Coordinate Transformations
11.3.7 Clipping
11.3.8 Transparency and Composition
11.4 Raster Images
11.4.1 Readers and Writers for Images
11.4.1.1 Obtaining Readers and Writers for Image File Types
11.4.1.2 Reading and Writing Files with Multiple Images
11.4.2 Image Manipulation
11.4.2.1 Constructing Raster Images
11.4.2.2 Filtering Images
11.5 Printing
11.5.1 Graphics Printing
11.5.2 Multiple-Page Printing
11.5.3 Print Services
11.5.4 Stream Print Services
11.5.5 Printing Attributes
Chapter 12: Native Methods
12.1 Calling a C Function from a Java Program
12.2 Numeric Parameters and Return Values
12.3 String Parameters
12.4 Accessing Fields
12.4.1 Accessing Instance Fields
12.4.2 Accessing Static Fields
12.5 Encoding Signatures
12.6 Calling Java Methods
12.6.1 Instance Methods
12.6.2 Static Methods
12.6.3 Constructors
12.6.4 Alternative Method Invocations
12.7 Accessing Array Elements
12.8 Handling Errors
12.9 Using the Invocation API
12.10 A Complete Example: Accessing the Windows Registry
12.10.1 Overview of the Windows Registry
12.10.2 A Java Platform Interface for Accessing the Registry
12.10.3 Implementation of Registry Access Functions as Native
Methods
12.11 Foreign Functions: A Glimpse into the Future
Preface
To the Reader
The book you have in your hands is the second volume of the twelfth
edition of Core Java, fully updated for Java SE 17. The first volume covers
the essential features of the language; this volume deals with the advanced
topics that a programmer needs to know for professional software
development. Thus, as with the first volume and the previous editions of
this book, we are still targeting programmers who want to put Java
technology to work in real projects.
As is the case with any book, errors and inaccuracies are inevitable. Should
you find any in this book, we would very much like to hear about them. Of
course, we would prefer to hear about them only once. For this reason, we
have put up a web site at http://horstmann.com/corejava with a
FAQ, bug fixes, and workarounds. Strategically placed at the end of the bug
report web page (to encourage you to read the previous reports) is a form
that you can use to report bugs or problems and to send suggestions for
improvements for future editions.
About This Book
The chapters in this book are, for the most part, independent of each other.
You should be able to delve into whatever topic interests you the most and
read the chapters in any order.
In Chapter 1, you will learn all about the Java stream library that brings a
modern flavor to processing data, by specifying what you want without
describing in detail how the result should be obtained. This allows the
stream library to focus on an optimal evaluation strategy, which is
particularly advantageous for optimizing concurrent computations.
The topic of Chapter 2 is input and output handling (I/O). In Java, all input
and output is handled through input/output streams. These streams (not to
be confused with those in Chapter 1) let you deal, in a uniform manner,
with communications among various sources of data, such as files, network
connections, or memory blocks. We include detailed coverage of the reader
and writer classes that make it easy to deal with Unicode. We show you
what goes on under the hood when you use the object serialization
mechanism, which makes saving and loading objects easy and convenient.
We then move on to regular expressions and working with files and paths.
Throughout this chapter, you will find welcome enhancements in recent
Java versions.
Chapter 3 covers XML. We show you how to parse XML files, how to
generate XML, and how to use XSL transformations. As a useful example,
we show you how to specify the layout of a Swing form in XML. We also
discuss the XPath API, which makes finding needles in XML haystacks
much easier.
Chapter 4 covers the networking API. Java makes it phenomenally easy to
do complex network programming. We show you how to make network
connections to servers, how to implement your own servers, and how to
make HTTP connections. This chapter includes coverage of the new HTTP
client.
Chapter 5 covers database programming. The focus is on JDBC, the Java
database connectivity API that lets Java programs connect to relational
databases. We show you how to write useful programs to handle realistic
database chores, using a core subset of the JDBC API. (A complete
treatment of the JDBC API would require a book almost as big as this one.)
Java had two prior attempts at libraries for handling date and time. The
third one was the charm in Java 8. In Chapter 6, you will learn how to deal
with the complexities of calendars and time zones, using the new date and
time library.
Chapter 7 discusses a feature that we believe can only grow in importance:
internationalization. The Java programming language is one of the few
languages designed from the start to handle Unicode, but the
internationalization support on the Java platform goes much further. As a
result, you can internationalize Java applications so that they cross not only
platforms but country boundaries as well. For example, we show you how
to write a retirement calculator that uses either English, German, or Chinese
languages.
Chapter 8 discusses three techniques for processing code. The scripting
and compiler APIs allow your program to call code in scripting languages
such as JavaScript or Groovy, and to compile Java code. Annotations allow
you to add arbitrary information (sometimes called metadata) to a Java
program. We show you how annotation processors can harvest these
annotations at the source or class file level, and how annotations can be
used to influence the behavior of classes at runtime. Annotations are only
useful with tools, and we hope that our discussion will help you select
useful annotation processing tools for your needs.
In Chapter 9, you will learn about the Java Platform Module System that
was introduced in Java 9 to facilitate an orderly evolution of the Java
platform and core libraries. This module system provides encapsulation for
packages and a mechanism for describing module requirements. You will
learn the properties of modules so that you can decide whether to use them
in your own applications. Even if you decide not to, you need to know the
new rules so that you can interact with the Java platform and other
modularized libraries.
Chapter 10 takes up the Java security model, user authentication, and the
cryptographic functions in the Java security library. You will learn about
important features as message and code signing, authorization and
authentication, and encryption. We conclude with examples that use the
AES and RSA encryption algorithms.
Chapter 11 contains all the Swing material that didn’t make it into Volume
I, especially the important but complex tree and table components. We also
cover the Java 2D API, which you can use to create realistic drawings and
special effects. Of course, not many programmers need to program Swing
user interfaces these days, so we pay particular attention to features that are
useful for images that can be generated on a server.
Chapter 12 takes up native methods, which let you call methods written for
a specific machine such as the Microsoft Windows API. Obviously, this
feature is controversial: Use native methods, and the cross-platform nature
of Java vanishes. Nonetheless, every serious programmer writing Java
applications for specific platforms needs to know these techniques. At
times, you need to turn to the operating system’s API for your target
platform when you interact with a device or service that is not supported by
Java. We illustrate this by showing you how to access the registry API in
Windows from a Java program.
As always, all chapters have been completely revised for the latest version
of Java. Outdated material has been removed, and the new APIs up to Java
17 are covered in detail.
Conventions
As is common in many computer books, we use monospace type to
represent computer code.
Note
Notes are tagged with “note” icons that look like this.
Tip
Tips are tagged with “tip” icons that look like this.
Caution
When there is danger ahead, we warn you with a “caution” icon.
C++ Note:
There are a number of C++ notes that explain the difference between the
Java programming language and C++. You can skip them if you aren’t
interested in C++.
Java comes with a large programming library, or Application Programming
Interface (API). When using an API call for the first time, we add a short
summary description at the end of the section. These descriptions are a bit
more informal but, we hope, also a little more informative than those in the
official online API documentation. The names of interfaces are in italics,
just like in the official documentation. The number after a class, interface,
or method name is the JDK version in which the feature was introduced.
Application Programming Interface 1.2
Programs whose source code is included in the companion code for this
book are listed as examples, for instance
Listing 1.1 ScriptTest.java
You can download the companion code from
http://horstmann.com/corejava.
Register your copy of Core Java, Volume II—Advanced Features,
Eleventh Edition, on the InformIT site for convenient access to
updates and/or corrections as they become available. To start the
registration process, go to informit.com/register and log in
or create an account. Enter the product ISBN (9780135166314) and
click Submit. Look on the Registered Products tab for an Access
Bonus Content link next to this product, and follow that link to access
any available bonus materials. If you would like to be notified of
exclusive offers on new editions and updates, please check the box to
receive email from us.
Acknowledgments
Writing a book is always a monumental effort, and rewriting doesn’t seem
to be much easier, especially with such a rapid rate of change in Java
technology. Making a book a reality takes many dedicated people, and it is
my great pleasure to acknowledge the contributions of the entire Core Java
team.
A large number of individuals at Pearson provided valuable assistance, but
they managed to stay behind the scenes. I’d like them all to know how
much I appreciate their efforts. As always, my warm thanks go to my editor,
Greg Doench, for steering the book through the writing and production
process, and for allowing me to be blissfully unaware of the existence of all
those folks behind the scenes. I am very grateful to Julie Nahil for
production support, and to Dmitry Kirsanov and Alina Kirsanova for
copyediting and typesetting the manuscript.
Thanks to the many readers of earlier editions who reported embarrassing
errors and made lots of thoughtful suggestions for improvement. I am
particularly grateful to the excellent reviewing team that went over the
manuscript with an amazing eye for detail and saved me from many more
embarrassing errors.
Reviewers of this and earlier editions include Chuck Allison (Utah Valley
University), Lance Andersen (Oracle), Gail Anderson (Anderson Software
Group), Paul Anderson (Anderson Software Group), Alec Beaton (IBM),
Cliff Berg, Andrew Binstock (Oracle), Joshua Bloch, David Brown, Corky
Cartwright, Frank Cohen (PushToTest), Chris Crane (devXsolution), Dr.
Nicholas J. De Lillo (Manhattan College), Rakesh Dhoopar (Oracle),
Robert Evans (Senior Staff, The Johns Hopkins University Applied Physics
Lab), David Geary (Clarity Training), Jim Gish (Oracle), Brian Goetz
(Oracle), Angela Gordon, Dan Gordon (Electric Cloud), Rob Gordon, John
Gray (University of Hartford), Cameron Gregory (olabs.com), Steve
Haines, Marty Hall (coreservlets.com, Inc.), Vincent Hardy (Adobe
Systems), Dan Harkey (San Jose State University), William Higgins (IBM),
Marc Hoffmann (mtrail), Vladimir Ivanovic (PointBase), Jerry Jackson (CA
Technologies), Heinz Kabutz (Java Specialists), Stepan V. Kalinin (I-
Teco/Servionica LTD), Tim Kimmet (Walmart), Chris Laffra, Charlie Lai
(Apple), Angelika Langer, Jeff Langr (Langr Software Solutions), Doug
Langston, Hang Lau (McGill University), Mark Lawrence, Doug Lea
(SUNY Oswego), Gregory Longshore, Bob Lynch (Lynch Associates),
Philip Milne (consultant), Mark Morrissey (The Oregon Graduate Institute),
Mahesh Neelakanta (Florida Atlantic University), José Paumard (Oracle),
Hao Pham, Paul Philion, Blake Ragsdell, Ylber Ramadani (Ryerson
University), Stuart Reges (University of Arizona), Simon Ritter (Azul
Systems), Rich Rosen (Interactive Data Corporation), Peter Sanders (ESSI
University, Nice, France), Dr. Paul Sanghera (San Jose State University and
Brooks College), Paul Sevinc (Teamup AG), Devang Shah (Sun
Microsystems), Yoshiki Shibata, Richard Slywczak (NASA/Glenn Research
Center), Bradley A. Smith, Steven Stelting (Oracle), Christopher Taylor,
Luke Taylor (Valtech), George Thiruvathukal, Kim Topley
(StreamingEdge), Janet Traub, Paul Tyma (consultant), Christian
Ullenboom, Peter van der Linden, Burt Walsh, Joe Wang (Oracle), Dan Xu
(Oracle), and John Zavgren (Oracle).
Cay Horstmann
Berlin, Germany
December 2021
Chapter 1: Streams
In this chapter
• 1.1 From Iterating to Stream Operations
• 1.2 Stream Creation
• 1.3 The filter, map, and flatMap Methods
• 1.4 Extracting Substreams and Combining Streams
• 1.5 Other Stream Transformations
• 1.6 Simple Reductions
• 1.7 The Optional Type
• 1.8 Collecting Results
• 1.9 Collecting into Maps
• 1.10 Grouping and Partitioning
• 1.11 Downstream Collectors
• 1.12 Reduction Operations
• 1.13 Primitive Type Streams
• 1.14 Parallel Streams
Compared to collections, streams provide a view of data that lets you
specify computations at a higher conceptual level. With a stream, you
specify what you want to have done, not how to do it. You leave the
scheduling of operations to the implementation. For example, suppose you
want to compute the average of a certain property. You specify the source of
data and the property, and the stream library can then optimize the
computation, for example by using multiple threads for computing sums
and counts and combining the results.
In this chapter, you will learn how to use the Java stream library, which was
introduced in Java 8, to process collections in a “what, not how” style.
1.1 From Iterating to Stream
Operations
When you process a collection, you usually iterate over its elements and do
some work with each of them. For example, suppose we want to count all
long words in a book. First, let’s put them into a list:
var contents = Files.readString(Path.of("alice.txt"))); // Read
file into string
List<String> words = List.of(contents.split("PL+"));
// Split into words; nonletters are delimiters
Now we are ready to iterate:
int count = 0;
for (String w : words)
{
if (w.length() > 12) count++;
}
With streams, the same operation looks like this:
long count = words.stream()
.filter(w -> w.length() > 12)
.count();
Now you don’t have to scan the loop for evidence of filtering and counting.
The method names tell you right away what the code intends to do.
Moreover, where the loop prescribes the order of operations in complete
detail, a stream is able to schedule the operations any way it wants, as long
as the result is correct.
Simply changing stream to parallelStream allows the stream library
to do the filtering and counting in parallel.
long count = words.parallelStream()
.filter(w -> w.length() > 12)
.count();
Streams follow the “what, not how” principle. In our stream example, we
describe what needs to be done: get the long words and count them. We
don’t specify in which order, or in which thread, this should happen. In
contrast, the loop at the beginning of this section specifies exactly how the
computation should work, and thereby forgoes any chances of optimization.
A stream seems superficially similar to a collection, allowing you to
transform and retrieve data. But there are significant differences:
1. A stream does not store its elements. They may be stored in an
underlying collection or generated on demand.
2. Stream operations don’t mutate their source. For example, the filter
method does not remove elements from a stream but yields a new stream
in which they are not present.
3. Stream operations are lazy when possible. This means they are not
executed until their result is needed. For example, if you only ask for the
first five long words instead of all, the filter method will stop filtering
after the fifth match. As a consequence, you can even have infinite
streams!
Let us have another look at the example. The stream and
parallelStream methods yield a stream for the words list. The
filter method returns another stream that contains only the words of
length greater than twelve. The count method reduces that stream to a
result.
This workflow is typical when you work with streams. You set up a pipeline
of operations in three stages:
1. Create a stream.
2. Specify intermediate operations for transforming the initial stream into
others, possibly in multiple steps.
3. Apply a terminal operation to produce a result. This operation forces the
execution of the lazy operations that precede it. Afterwards, the stream
can no longer be used.
In the example in Listing 1.1, the stream is created with the stream or
parallelStream method. The filter method transforms it, and
count is the terminal operation.
In the next section, you will see how to create a stream. The subsequent
three sections deal with stream transformations. They are followed by five
sections on terminal operations.
Listing 1.1 streams/CountLongWords.java
1 package streams;
2
3 import java.io.*;
4 import java.nio.file.*;
5 import java.util.*;
6
7 /**
8 * @version 1.02 2019-08-28
9 * @author Cay Horstmann
10 */
11 public class CountLongWords
12 {
13 public static void main(String[] args) throws IOException
14 {
15 var contents = Files.readString(
16 Path.of("../gutenberg/alice30.txt"));
17 List<String> words = List.of(contents.split("PL+"));
18
19 long count = 0;
20 for (String w : words)
21 {
22 if (w.length() > 12) count++;
23 }
24 System.out.println(count);
25
26 count = words.stream().filter(w -> w.length() >
12).count();
27 System.out.println(count);
28
29 count = words.parallelStream().filter(w -> w.length() >
12).count();
30 System.out.println(count);
31 }
32 }
java.util.stream.Stream<T> 8
• Stream<T> filter(Predicate<? super T> p)
yields a stream containing all elements of this stream fulfilling p.
• long count()
yields the number of elements of this stream. This is a terminal
operation.
java.util.Collection<E> 1.2
• default Stream<E> stream()
• default Stream<E> parallelStream()
yield a sequential or parallel stream of the elements in this
collection.
1.2 Stream Creation
You have already seen that you can turn any collection into a stream with
the stream method of the Collection interface. If you have an array,
use the static Stream.of method instead.
Stream<String> words = Stream.of(contents.split("PL+"));
// split returns a String[] array
The of method has a varargs parameter, so you can construct a stream from
any number of arguments:
Stream<String> song = Stream.of("gently", "down", "the",
"stream");
Use Arrays.stream(array, from, to) to make a stream from a
part of an array.
To make a stream with no elements, use the static Stream.empty
method:
Stream<String> silence = Stream.empty();
// Generic type <String> is inferred; same as Stream.
<String>empty()
The Stream interface has two static methods for making infinite streams.
The generate method takes a function with no arguments (or,
technically, an object of the Supplier<T> interface). Whenever a stream
value is needed, that function is called to produce a value. You can get a
stream of constant values as
Stream<String> echos = Stream.generate(() -> "Echo");
or a stream of random numbers as
Stream<Double> randoms = Stream.generate(Math::random);
To produce sequences such as 0 1 2 3 . . ., use the iterate
method instead. It takes a “seed” value and a function (technically, a
UnaryOperator<T>) and repeatedly applies the function to the previous
result. For example,
Stream<BigInteger> integers
= Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
The first element in the sequence is the seed BigInteger.ZERO. The
second element is f(seed) which yields 1 (as a big integer). The next
element is f(f(seed)) which yields 2, and so on.
To produce a finite stream instead, add a predicate that specifies when the
iteration should finish:
var limit = new BigInteger("10000000");
Stream<BigInteger> integers
= Stream.iterate(BigInteger.ZERO,
n -> n.compareTo(limit) < 0,
n -> n.add(BigInteger.ONE));
As soon as the predicate rejects an iteratively generated value, the stream
ends.
Finally, the Stream.ofNullable method makes a really short stream
from an object. The stream has length 0 if the object is null or length 1
otherwise, containing just the object. This is mostly useful in conjunction
with flatMap—see Section 1.7.7, “Turning an Optional into a Stream,”
on p. 23 for an example.
Note
A number of methods in the Java API yield streams. For example, the
String class has a lines method that yields a stream of the lines
contained in the string:
Stream<String> greetings = "HellonGuten TagnBonjour".lines()
The Pattern class has a method splitAsStream that splits a
CharSequence by a regular expression. You can use the following
statement to split a string into words:
Stream<String> words =
Pattern.compile("PL+").splitAsStream(contents);
The Scanner.tokens method yields a stream of tokens of a scanner.
Another way to get a stream of words from a string is
Stream<String> words = new Scanner(contents).tokens();
The static Files.lines method returns a Stream of all lines in a
file:
try (Stream<String> lines = Files.lines(path)) {
Process lines
}
To view the contents of one of the streams introduced in this section, use
the toList method, which collects the stream’s elements in a list. Like
count, toList is a terminal operation. If the stream is infinite, first
truncate it with the limit method:
System.out.println(Stream.generate(Math::random)
.limit(10).toList());
Note
If you have an Iterable that is not a collection, you can turn it into a
stream by calling
StreamSupport.stream(iterable.spliterator(), false);
If you have an Iterator and want a stream of its results, use
StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iterator, Spliterator.ORDERED), false);
Caution
It is very important that you don’t modify the collection backing a
stream while carrying out a stream operation. Remember that streams
don’t collect their data—the data is always in a separate collection. If
you modify that collection, the outcome of the stream operations
becomes undefined. The JDK documentation refers to this requirement
as noninterference.
To be exact, since intermediate stream operations are lazy, it is possible
to mutate the collection up to the point where the terminal operation
executes. For example, the following, while certainly not recommended,
will work:
List<String> wordList = . . .;
Stream<String> words = wordList.stream();
wordList.add("END");
long n = words.distinct().count();
But this code is wrong:
Stream<String> words = wordList.stream();
words.forEach(s -> {if (s.length() < 12) wordList.remove(s);});
// ERROR--interference
The example program in Listing 1.2 shows the various ways of creating a
stream.
Listing 1.2 streams/CreatingStreams.java
1 package streams;
2
3 import java.io.*;
4 import java.math.*;
5 import java.nio.file.*;
6 import java.util.*;
7 import java.util.regex.Pattern;
8 import java.util.stream.*;
9
10 /**
11 * @version 1.03 2021-09-06
12 * @author Cay Horstmann
13 */
14 public class CreatingStreams
15 {
16 public static <T> void show(String title, Stream<T>
stream)
17 {
18 final int SIZE = 10;
19 List<T> firstElements = stream
20 .limit(SIZE + 1)
21 .toList();
22 System.out.print(title + ": ");
23 for (int i = 0; i < firstElements.size(); i++)
24 {
25 if (i > 0) System.out.print(", ");
26 if (i < SIZE)
System.out.print(firstElements.get(i));
27 else System.out.print("...");
28 }
29 System.out.println();
30 }
31
32 public static void main(String[] args) throws IOException
33 {
34 Path path = Path.of("../gutenberg/alice30.txt");
35 var contents = Files.readString(path);
36
37 Stream<String> words =
Stream.of(contents.split("PL+"));
38 show("words", words);
39 Stream<String> song = Stream.of("gently", "down",
"the", "stream");
40 show("song", song);
41 Stream<String> silence = Stream.empty();
42 show("silence", silence);
43
44 Stream<String> echos = Stream.generate(() -> "Echo");
45 show("echos", echos);
46
47 Stream<Double> randoms = Stream.generate(Math::random);
48 show("randoms", randoms);
49
50 Stream<BigInteger> integers =
Stream.iterate(BigInteger.ONE,
51 n -> n.add(BigInteger.ONE));
52 show("integers", integers);
53
54 Stream<String> greetings = "HellonGuten
TagnBonjour".lines();
55 show("greetings", greetings);
56
57 Stream<String> wordsAnotherWay =
Pattern.compile("PL+").splitAsStream(contents);
58 show("wordsAnotherWay", wordsAnotherWay);
59
60 try (Stream<String> lines = Files.lines(path))
61 {
62 show("lines", lines);
63 }
64
65 Iterable<Path> iterable =
FileSystems.getDefault().getRootDirectories();
66 Stream<Path> rootDirectories =
StreamSupport.stream(iterable.spliterator(), false);
67 show("rootDirectories", rootDirectories);
68
69 Iterator<Path> iterator =
Path.of("/usr/share/dict/words").iterator();
70 Stream<Path> pathComponents =
StreamSupport.stream(Spliterators.spliteratorUnknownSize(
71 iterator, Spliterator.ORDERED), false);
72 show("pathComponents", pathComponents);
73 }
74 }
java.util.stream.Stream 8
• static <T> Stream<T> of(T... values)
yields a stream whose elements are the given values.
• static <T> Stream<T> empty()
yields a stream with no elements.
• static <T> Stream<T> generate(Supplier<T> s)
yields an infinite stream whose elements are constructed by
repeatedly invoking the function s.
• static <T> Stream<T> iterate(T seed,
UnaryOperator<T> f)
• static <T> Stream<T> iterate(T seed,
Predicate<? super T> hasNext, UnaryOperator<T>
f)
yield a stream whose elements are seed, f invoked on seed, f invoked
on the preceding element, and so on. The first method yields an
infinite stream. The stream of the second method comes to an end
before the first element that doesn’t fulfill the hasNext predicate.
• static <T> Stream<T> ofNullable(T t) 9
returns an empty stream if t is null or a stream containing t
otherwise.
java.util.Spliterators 8
• static <T> Spliterator<T>
spliteratorUnknownSize(Iterator<? extends T>
iterator, int characteristics)
turns an iterator into a splittable iterator of unknown size with the
given characteristics (a bit pattern containing constants such as
Spliterator.ORDERED).
java.util.Arrays 1.2
• static <T> Stream<T> stream(T[] array, int
startInclusive, int endExclusive) 8
yields a stream whose elements are the specified range of the array.
java.lang.String
• static Stream<String> lines() 11
yields a stream whose elements are the lines of this string.
java.util.regex.Pattern 1.4
• Stream<String> splitAsStream(CharSequence input) 8
yields a stream whose elements are the parts of the input that are
delimited by this pattern.
java.nio.file.Files 7
• static Stream<String> lines(Path path) 8
• static Stream<String> lines(Path path, Charset
cs) 8
yield a stream whose elements are the lines of the specified file, with
the UTF-8 charset or the given charset.
java.util.stream.StreamSupport 8
• static <T> Stream<T> stream(Spliterator<T>
spliterator, boolean parallel)
yields a stream containing the values produced by the given
splittable iterator.
java.lang.Iterable 5
• Spliterator<T> spliterator() 8
yields a splittable iterator for this Iterable. The default
implementation does not split and does not report a size.
java.util.Scanner 5
• public Stream<String> tokens() 9
yields a stream of strings returned by calling the next method of this
scanner.
java.util.function.Supplier<T> 8
• T get()
supplies a value.
1.3 The filter, map, and flatMap
Methods
A stream transformation produces a stream whose elements are derived
from those of another stream. You have already seen the filter
transformation that yields a new stream with those elements that match a
certain condition. Here, we transform a stream of strings into another
stream containing only long words:
List<String> words = . . .;
Stream<String> longWords = words.stream().filter(w -> w.length()
> 12);
The argument of filter is a Predicate<T>—that is, a function from T to
boolean.
Often, you want to transform the values in a stream in some way. Use the
map method and pass the function that carries out the transformation. For
example, you can transform all words to lowercase like this:
Stream<String> lowercaseWords =
words.stream().map(String::toLowerCase);
Here, we used map with a method reference. Often, you will use a lambda
expression instead:
Stream<String> firstLetters = words.stream().map(s ->
s.substring(0, 1));
The resulting stream contains the first letter of each word.
When you use map, a function is applied to each element, and the result is a
new stream with the results. Occasionally, you are faced with a mapping
function that generates an optional result, or more than one result. As an
example, consider a method codePoints that yields all code points of a
string. For example, codePoints("Hello ") would consist of "H",
"e", "l", "l", "o", " ", " ". Note that the globe symbol (U+1F310)
consists of two char values, so the codePoints method has to do some
heavy lifting to make this happen. We will look at a couple of
implementations momentarily.
How should codePoints collect its multiple results? For the stream API,
it is most natural if the method returns a Stream<String>.
Now let’s map such a codePoints method on a stream of strings:
Stream<Stream<String>> result = words.stream().map(w ->
codePoints(w));
You will get a stream of streams, like [. . . ["y", "o", "u",
"r"], ["b", "o", "a", "t"], . . .]. To flatten it out to a
single stream [. . . "y", "o", "u", "r", "b", "o", "a",
"t", . . .], use the flatMap method instead of map:
Stream<String> flatResult = words.stream().flatMap(w ->
codePoints(w));
// Calls codePoints on each word and flattens the results
Now that you have seen how to use the codePoints method, how do you
write it? The String class has a codePoints method that yields a
stream of integer code points:
"Hello ".codePoints() // A stream of integers 72, 101, 108, 108,
111, 32, 127760
Next, we need to transform each of the integers to a string containing the
Unicode character with the given code point. Unfortunately, there is a
technical difficulty. The codePoints method produces an IntStream,
which is a little different from a Stream<Integer>, as you will see in
Section 1.13, “Primitive Type Streams,” on p. 43. Instead of map, you use
the mapToObj method to transform the elements. Perhaps surprisingly,
there is no convenient method for turning an integer codepoint into a string.
Here is the best I could come up with:
public static Stream<String> codePoints(String s)
{
return s.codePoints().mapToObj(cp -> new String(new int [] {
cp }, 0, 1));
}
When using flatMap, you provide a method that produces a new stream
for every stream element. As you have seen, that can be tedious. It can also
be a little inefficient. The mapMulti method offers an alternative. Instead
of producing a stream of results, you generate the results and pass them to a
collector—an object of a class implementing the functional interface
Consumer. For each result, invoke the collector’s accept method.
Let’s do this with an example. The following loop produces the code points
of a string s:
int i = 0;
while (i < s.length())
{
int cp = sentence.codePointAt(i);
// Do something with cp
if (Character.isSupplementaryCodePoint(cp)) i += 2;
else i++;
}
When calling mapMulti, you provide a function that is invoked with the
stream element and the collector. In your function, pass your results to the
collector.
Stream<String> result = words.stream().mapMulti((s, collector) ->
{
int i = 0;
while (i < s.length())
{
int cp = sentence.codePointAt(i);
collector.accept(cp);
if (Character.isSupplementaryCodePoint(cp)) i += 2;
else i++;
}
});
java.util.stream.Stream 8
• Stream<T> filter(Predicate<? super T>
predicate)
yields a stream containing the elements of this stream that fulfill the
predicate.
• <R> Stream<R> map(Function<? super T,? extends
R> mapper)
yields a stream containing the results of applying mapper to the
elements of this stream.
• <R> Stream<R> flatMap(Function<? super T,?
extends Stream<? extends R>> mapper)
yields a stream obtained by concatenating the results of applying
mapper to the elements of this stream. (Note that each mapper
result is a stream.)
• <R> Stream<R> mapMulti(BiConsumer<? super T,?
super Consumer<R>> mapper) 16
For each stream element, the mapper is invoked , and all elements
passed to the Consumer during invocation are added to the result
stream.
1.4 Extracting Substreams and
Combining Streams
The call stream.limit(n) returns a new stream that ends after n
elements (or when the original stream ends if it is shorter). This method is
particularly useful for cutting infinite streams down to size. For example,
Stream<Double> randoms =
Stream.generate(Math::random).limit(100);
yields a stream with 100 random numbers.
The call stream.skip(n) does the exact opposite. It discards the first n
elements. This is handy in our book reading example where, due to the way
the split method works, the first element is an unwanted empty string.
We can make it go away by calling skip:
Stream<String> words =
Stream.of(contents.split("PL+")).skip(1);
The stream.takeWhile(predicate) call takes all elements from the
stream while the predicate is true, and then stops.
For example, suppose we use the codePoints method of the preceding
section to split a string into characters, and we want to collect all initial
digits. The takeWhile method can do this:
Stream<String> initialDigits = codePoints(str).takeWhile(
s -> "0123456789".contains(s));
The dropWhile method does the opposite, dropping elements while a
condition is true and yielding a stream of all elements starting with the first
one for which the condition was false. For example,
Stream<String> withoutInitialWhiteSpace =
codePoints(str).dropWhile(
s -> s.strip().length() == 0);
You can concatenate two streams with the static concat method of the
Stream class:
Stream<String> combined = Stream.concat(
codePoints("Hello"), codePoints("World"));
// Yields the stream ["H", "e", "l", "l", "o", "W", "o", "r",
"l", "d"]
Of course, the first stream should not be infinite—otherwise the second one
wouldn’t ever get a chance.
java.util.stream.Stream 8
• Stream<T> limit(long maxSize)
yields a stream with up to maxSize of the initial elements from this
stream.
• Stream<T> skip(long n)
yields a stream whose elements are all but the initial n elements of
this stream.
• Stream<T> takeWhile(Predicate<? super T>
predicate) 9
yields a stream whose elements are the initial elements of this stream
that fulfill the predicate.
• Stream<T> dropWhile(Predicate<? super T>
predicate) 9
yields a stream whose elements are the elements of this stream
except for the initial ones that do not fulfill the predicate.
• static <T> Stream<T> concat(Stream<? extends
T> a, Stream<? extends T> b)
yields a stream whose elements are the elements of a followed by
the elements of b.
1.5 Other Stream Transformations
The distinct method returns a stream that yields elements from the
original stream, in the same order, except that duplicates are suppressed.
The duplicates need not be adjacent.
Stream<String> uniqueWords
= Stream.of("merrily", "merrily", "merrily",
"gently").distinct();
// Only one "merrily" is retained
For sorting a stream, there are several variations of the sorted method.
One works for streams of Comparable elements, and another accepts a
Comparator. Here, we sort strings so that the longest ones come first:
Stream<String> longestFirst
=
words.stream().sorted(Comparator.comparing(String::length).revers
ed());
As with all stream transformations, the sorted method yields a new
stream whose elements are the elements of the original stream in sorted
order.
Of course, you can sort a collection without using streams. The sorted
method is useful when the sorting process is part of a stream pipeline.
Finally, the peek method yields another stream with the same elements as
the original, but a function is invoked every time an element is retrieved.
That is handy for debugging:
Object[] powers = Stream.iterate(1.0, p -> p * 2)
.peek(e -> System.out.println("Fetching " + e))
.limit(20).toArray();
When an element is actually accessed, a message is printed. This way you
can verify that the infinite stream returned by iterate is processed lazily.
Tip
When you use a debugger to debug a stream computation, you can set a
breakpoint in a method that is called from one of the transformations.
With most IDEs, you can also set breakpoints in lambda expressions. If
you just want to know what happens at a particular point in the stream
pipeline, add
.peek(x -> {
return; })
and set a breakpoint on the second line.
java.util.stream.Stream 8
• Stream<T> distinct()
yields a stream of the distinct elements of this stream.
• Stream<T> sorted()
• Stream<T> sorted(Comparator<? super T>
comparator)
yield a stream whose elements are the elements of this stream in
sorted order. The first method requires that the elements are
instances of a class implementing Comparable.
• Stream<T> peek(Consumer<? super T> action)
yields a stream with the same elements as this stream, passing each
element to action as it is consumed.
1.6 Simple Reductions
Now that you have seen how to create and transform streams, we will
finally get to the most important point—getting answers from the stream
data. The methods covered in this section are called reductions. Reductions
are terminal operations. They reduce the stream to a nonstream value that
can be used in your program.
You have already seen a simple reduction: the count method that returns
the number of elements of a stream.
Other simple reductions are max and min that return the largest or smallest
value. There is a twist—these methods return an Optional<T> value that
either wraps the answer or indicates that there is none (because the stream
happened to be empty). In the olden days, it was common to return null in
such a situation. But that can lead to null pointer exceptions when it
happens in an incompletely tested program. The Optional type is a better
way of indicating a missing return value. We discuss the Optional type
in detail in the next section. Here is how you can get the maximum of a
stream:
Optional<String> largest =
words.max(String::compareToIgnoreCase);
System.out.println("largest: " + largest.orElse(""));
The findFirst returns the first value in a nonempty collection. It is often
useful when combined with filter. For example, here we find the first
word that starts with the letter Q, if it exists:
Optional<String> startsWithQ
= words.filter(s -> s.startsWith("Q")).findFirst();
If you are OK with any match, not just the first one, use the findAny
method. This is effective when you parallelize the stream, since the stream
can report any match that it finds instead of being constrained to the first
one.
Optional<String> startsWithQ
= words.parallel().filter(s -> s.startsWith("Q")).findAny();
If you just want to know if there is a match, use anyMatch. That method
takes a predicate argument, so you won’t need to use filter.
boolean aWordStartsWithQ
= words.parallel().anyMatch(s -> s.startsWith("Q"));
There are methods allMatch and noneMatch that return true if all or
no elements match a predicate. These methods also benefit from being run
in parallel.
java.util.stream.Stream 8
• Optional<T> max(Comparator<? super T>
comparator)
• Optional<T> min(Comparator<? super T>
comparator)
yield a maximum or minimum element of this stream, using the
ordering defined by the given comparator, or an empty Optional
if this stream is empty. These are terminal operations.
• Optional<T> findFirst()
• Optional<T> findAny()
yield the first, or any, element of this stream, or an empty
Optional if this stream is empty. These are terminal operations.
• boolean anyMatch(Predicate<? super T>
predicate)
• boolean allMatch(Predicate<? super T>
predicate)
• boolean noneMatch(Predicate<? super T>
predicate)
return true if any, all, or none of the elements of this stream match
the given predicate. These are terminal operations.
1.7 The Optional Type
An Optional<T> object is a wrapper for either an object of type T or no
object. In the former case, we say that the value is present. The
Optional<T> type is intended as a safer alternative for a reference of
type T that either refers to an object or is null. But it is only safer if you
use it right. The next three sections shows you how.
1.7.1 Getting an Optional Value
The key to using Optional effectively is to use a method that either
produces an alternative if the value is not present, or consumes the value
only if it is present.
In this section, we look at the first strategy. Often, there is a default that you
want to use when there was no match, perhaps the empty string:
String result = optionalString.orElse("");
// The wrapped string, or "" if none
You can also invoke code to compute the default:
String result = optionalString.orElseGet(() ->
System.getProperty("myapp.default"));
// The function is only called when needed
Or you can throw an exception if there is no value:
String result =
optionalString.orElseThrow(IllegalStateException::new);
// Supply a method that yields an exception object
java.util.Optional 8
• T orElse(T other)
yields the value of this Optional, or other if this Optional is
empty.
• T orElseGet(Supplier<? extends T> other)
yields the value of this Optional, or the result of invoking other
if this Optional is empty.
• <X extends Throwable> T orElseThrow(Supplier<?
extends X> exceptionSupplier)
yields the value of this Optional, or throws the result of invoking
exceptionSupplier if this Optional is empty.
1.7.2 Consuming an Optional Value
In the preceding section, you saw how to produce an alternative if no value
is present. The other strategy for working with optional values is to
consume the value only if it is present.
The ifPresent method accepts a function. If the optional value exists, it
is passed to that function. Otherwise, nothing happens.
optionalValue.ifPresent(v -> Process v);
For example, if you want to add the value to a set if it is present, call
optionalValue.ifPresent(v -> results.add(v));
or simply
optionalValue.ifPresent(results::add);
If you want to take one action if the Optional has a value and another
action if it doesn’t, use ifPresentOrElse:
optionalValue.ifPresentOrElse(
v -> System.out.println("Found " + v),
() -> logger.warning("No match"));
java.util.Optional 8
• void ifPresent(Consumer<? super T> action)
If this Optional is nonempty, passes its value to action.
• void ifPresentOrElse(Consumer<? super T>
action, Runnable emptyAction) 9
If this Optional is nonempty, passes its value to action, else
invokes emptyAction.
1.7.3 Pipelining Optional Values
In the preceding sections, you saw how to get a value out of an Optional
object. Another useful strategy is to keep the Optional intact. You can
transform the value inside an Optional by using the map method:
Optional<String> transformed =
optionalString.map(String::toUpperCase);
If optionalString is empty, then transformed is also empty.
Here is another example. We add a result to a list if it is present:
optionalValue.map(results::add);
If optionalValue is empty, nothing happens.
Note
This map method is the analog of the map method of the Stream
interface that you have seen in Section 1.3, “The filter, map, and
flatMap Methods,” on p. 11. Simply imagine an optional value as a
Random documents with unrelated
content Scribd suggests to you:
"Do you know that lady!" I heard them ask.
"Yes, and the nigger too. It's Miss Salome Poillon, and she lives at S
—— plantation, across the river," was the answer.
"Then she is a resident here, and there is no danger of their being
spies?" put in the cautious one.
"Lord, no! Why, she's the biggest Rebel 'round. So's all the family,
an' she's got a Rebel lover," replied my champion emphatically,
adding the last fact as if it were a clincher.
That settled it, and the two officers then came over to the carriage
and told me I was at liberty to go on, and regretted that they had
been obliged to stop me at all. I thanked them, and asked if I would
have much difficulty in getting through.
"I am afraid so," replied the one who had first met me.
"This is your most direct route, is it not?" asked the older officer, on
whom the rest of the conversation devolved.
"It is much the nearest way," I replied.
"It leads directly on, near where a considerable body of our troops
are, yet I think it will be safer for you to keep it than to try side
roads, where you would be constantly stopped. I will give you a note
to the general in command, and a pass, which will aid you until you
reach him. He will likely give you an escort for some distance," he
added, writing as he spoke.
When he handed me the papers, I asked him about the positions of
the Yankees, and in answering he told me also something new about
how Luce's army was located, which was one of the clues that I
wanted to learn.
I had no idea of using the papers unless I should fail in all efforts to
find Captain DeLacy. I told Ned not to refer to them in any way or to
our encounter, while he should be separated from me, and
impressed on him that he was not to get out of the buggy if he
could help it, or leave the horses one moment unless dragged away
by force. I regretted that we had run into the camp, for it took
valuable time, and it did not make me feel any better about it to
know that it had happened through my own carelessness. If I had
been watching out, as I ought to have been, I would have noticed
the fires in time to have avoided them by making a detour, and I
believed that I could have gotten later the valuable bit of information
the talkative officer had given me.
CHAPTER XI.
The encounter had one good result, however. It got us over our
stage fright, as it were, and rather raised us up to the grand climax.
We had driven nearly three miles farther before we ran into the
Rebel camp again. When we finally found ourselves making our way
under guard to General Dare's headquarters, we were far more
composed than we could possibly have been had we not already had
some experience.
When stopped, I had insisted on being allowed to proceed, but as I
expected and desired, the simple privilege of following my own way
was denied me. My statements regarding my identity were received
with incredulity. I insisted on the truth of my story, and I demanded
that I be taken to headquarters at once. After some parley, my
request was acceded to and a couple of soldiers took their places at
the horses' heads and slowly led them forward, while a guard walked
at the side of the buggy until we reached a cluster of tents pitched
somewhat apart, in front of which stood four or five officers
conversing.
The officer who had brought us in advanced to the group, and I
could hear him reporting the circumstances of our arrest. A
handsome subaltern came forward to assist me from the buggy, and
I was soon answering the curtly-put inquiries of the middle aged
officer to whom I had been conducted. I repeated my story. He
questioned and cross-questioned me severely, but I was too entirely
familiar with my ground to be caught tripping. I felt a good deal as if
I were an actor in a play, and while I must say that I did not
particularly admire the setting, I began to have an intense interest in
rendering my part well and having all go off smoothly.
Ned was seated in the buggy within hearing distance and I saw he
had assumed, or was really feeling, about the right amount of
anxiety, and that no one seemed to be paying any attention
whatever to him.
I did not recognize the officer interrogating me, but I heard him
addressed by one of the other officers as Colonel Sofield. When after
telling him my story, he utterly refused to credit it. I asked to see the
General in command. Col. Sofield replied that General Senhouse had
gone over to confer with General Leonard and might not be back
until morning, not for several hours certainly, and followed the
explanation with an intimation that both myself and my servant
would be well off under guard until his return.
I was somewhat nonplussed when the officer said General
Senhouse. I had looked on General Dare only as a guide to Captain
DeLacy, and had no interest whatever beyond that in him. At the
same time I was a trifle surprised that I had not been taken before
him, and that reference had not been made to him instead of to
General Senhouse. I began to wonder if it were possible that I had
not reached Dare's headquarters, but I did not dare ask directly or
betray more knowledge of army details than a girl would be likely to
know. After pondering a moment, I said:
"I ought perhaps to have stopped at A——, as I was advised to do,
but I was so very anxious to get on, that I could not make up my
mind to delay there. Will you tell me what regiment this is? I have
friends and relatives with General Luce and there may be some one
here who can identify me."
An orderly was presenting a paper to Col. Sofield as I finished
speaking, and another officer, who had come up but a short time
previous and was standing near, in company with the others,
answered:
"This is General Dare's division, but General Senhouse is in
command at present. Over on the left there is the —— Regiment,
—— Brigade; others are further on. If you will give the names of
your friends, and they are here, they can be sent for."
"Captain DeLacy is with General Dare. If I could see him, he would
assure you that I am just who I represent myself. He is a very
intimate friend of the family," I said, turning again to my first
interlocuter.
"Impossible," he replied, "Captain DeLacy has just started to inspect
a position several miles from here. There is no telling when he will
be back."
"Beg pardon, Colonel, but Captain DeLacy has not got off yet. He
passed us on the way over here, and I saw him go in Colonel
Lounsbery's tent a few minutes ago," spoke up another officer.
"There he comes now," he added, as a tall figure came out of a tent
near by.
Affairs progressed rapidly in the next few minutes. In less time than
I could write it, Captain DeLacy had been called over to identify me;
had done it, even to the satisfaction of the obdurate Colonel, and
beard the story of my detention, and my anxious request that I
might go on at once.
Captain DeLacy asked and received permission to take me into a
neighboring tent, where I could wait, freed from the gaze of those
who had gathered around to see what was going on, until he could
procure the passes necessary to insure my safe conduct through
their lines. Colonel Sofield, whose good manners had increased in
proportion to the strengthening of his convictions that I was not a
spy, told him to take me into General Dare's tent, as it was the
nearest one unoccupied, then to return to him for passes.
A moment later I was alone with the only man of them all who could
penetrate my disguise. His first words assured me that he had not
heard from Salome lately enough to imperil my statements. And his
hurried whispers of love and devotion, together with his grave
concern at my having undertaken a journey through that section at
so dangerous a time, proved that he accepted me in perfect good
faith.
Even at that desperate moment, at the touch of the Captain's lips I
was filled with an unholy glee.
Fortunately, he had little time to play the lover. Love and war are an
ill-matched couple, and except that both set at naught all interfering
laws, they have nothing in common. The latter never relaxes the
grasp of a master and exacts that all who serve him shall fulfill their
duty to the utmost, without delay or flinching, although by so doing
all pleasures, affections, ties of kindred and life itself are yielded up.
My expressed anxiety for his safety, and pretended impression that
he was on some dangerous raid, led Captain DeLacy to assure me
that he was with Luce, and to tell me what forces Luce had with
him, but no more about his future movements than I had already
gathered, which amounted to but little beyond a clue to the meaning
of General Middleworth's movement, which I had witnessed that
afternoon. I questioned as closely as I dared, but elicited nothing
further. My shrewdest efforts were a failure. I saw that he either had
not been informed of the object of the campaign, or felt bound not
to reveal it even to one whom he held as dear as he did Salome.
CHAPTER XII.
While conversing with Captain DeLacy, I had become as familiar with
the interior of the tent as I could by the light of one inferior candle
and the use of my eyes. There seemed nothing there to invite
investigation.
Even after Captain DeLacy had reluctantly left me, a closer
inspection revealed nothing more promising. I sat on a camp stool,
in a corner; near was a pile of blankets; a rough camp chair stood
between me and the bed; a bayonet stuck in the ground did duty for
a candlestick, and on an empty wooden box near me lay a paper-
covered book.
I had just had time to run a hasty glance through the book, when
the fly was raised and an officer entered. As was only natural, he
started when he saw me, then lifted his hat with a half-spoken
apology, tossed a newspaper carelessly on the bed, threw his
overcoat over the chair and went out again.
I recognized him instantly as General Dare. His actions and looks
struck me as those of a man who felt at odds with the world and
who was nursing a grievance, but I was too deeply concerned about
my own affairs to be more than casually impressed with what I
learned afterwards was the case.
It is a strange fact that in times of most intense suffering, deadly
peril and deepest thought, the eye will be attracted by the most
trivial objects. While I anxiously pondered my next move, my eye
mechanically followed in and out the fantastically curved line made
by the shadows cast by the pile of blankets, then by the edge of the
coat cape as it trailed along the floor. I had followed it almost to the
end when my gaze was arrested by a spot of color differing from the
rest. With a start, I realized that I was looking at a flat, long book. I
could not tell then and I cannot tell now whether it fell from the
overcoat or was lying there when I entered, but I do not see how it
could have been there at first and escaped my observation.
I determined at once to see the contents of that book. There was
not one instant to be lost. I well knew that even then some one
might be standing at the entrance and that the Captain would return
at any moment. But examine that book I must, even at the risk of
surprise, detection and death. It was the most critical moment I had
yet encountered. I had to think and act together.
Throwing myself at full length on the grassy floor, with my head
screened from the first glance of any one entering, intending to
feign a swoon if any one did come, I extended my arm above my
head, in the shelter of the chair, and had the book in my impatient
fingers.
Opening it hastily, I scanned it in the dim light which came over my
shoulder from the flickering candle. I was confronted by a series of
blank pages. General Dare's name was on the fly leaf. Only the first
three pages were written on, and they contained nothing except
detached items of interest to him only. Evidently, the book had been
newly purchased, for the dates ran but a few days back.
Bitterly disappointed, I ran over the pages again, and a folded paper
slipped into view. Even to this day I can distinctly feel the wild
bound of exultation my heart gave when I knew that I held in my
hands a copy of Special Order No. 000, issued by the Rebel
Commander in Chief only four days before, and regulating the
movements of all the divisions of his army for several days to come.
At the sight of that paper every drop of blood in my body seemed to
rush to my heart, only to leave it again with a wild speed that turned
me faint and dizzy. The letters danced before my eyes, but even in
that one hasty glance I took in enough to know that I need seek no
further information. I had succeeded even beyond my hopes and
expectations. If I could get safely back with that paper, and
whatever else I had learned, I felt check to the Rebels must be
insured.
Hastily concealing the paper, I pushed the book under the bed, and
had barely regained my place when Captain DeLacy re-entered with
the passes. There was no time for further private conversation
between us, which I regarded as a piece of good luck.
Captain DeLacy told me, while he hastily assorted the papers in his
hand, that he was obliged to proceed without delay on the important
duty for which he was preparing when Colonel Sofield had called him
to me; that as the first part of our way lay the same as his, he could
act as my escort until his road turned off from the one I was to
follow. From where he had to leave me, to H—— was only ten miles,
and he exacted a promise that I would remain there with friends
until morning.
I could not but be touched at his anxiety about me, impatient as I
was at the delay which it caused.
We started almost immediately. Captain DeLacy rode at the side of
the buggy and the squad of men with him a short distance in
advance. The road was clear, and we made excellent time.
At last the moment of separation came. His real farewell had already
been said, so before following his men down the dark path, into
which they had turned, the Captain paused only for some cautions
to Ned and a quickly spoken "good bye" to me, which held as much
as was ever put in that simple word.
I realized fully what the parting was to him. He had accepted me as
Salome, without doubt or question, and to leave me with no other
protector than Ned tried him sorely.
I leaned out of the buggy and looked back after him, with a feeling
of pain that surprised me. As he disappeared, a presentment that I
should never see him again crept over me, followed by an idle
speculation whether it was he or I who was first to meet our fate, a
feeling which I remembered well a few months later, when I
received the news that Captain DeLacy had been shot in battle.
CHAPTER XIII.
Shaking off the dim sense of foreboding, I gave my thoughts entirely
to the task before me. I had decided to make my way down the side
of the river I was then on. From what I had learned of the position
of the enemy, I knew the risk would be no greater than if I crossed
to the opposite shore, and I hoped to save many weary miles of
travel. Being well aware of the extreme caution shown on our side, I
thought the chances were that our army would be yet in the
neighborhood of the place where I left them, and I aimed for that
point.
I told Ned that I had secured a paper of the utmost importance, and
that if I were shot and he escaped, he was to take the paper from
its place of concealment and carry it on.
We turned to the left, down the first road we came to, after parting
with Captain DeLacy and his men. Just before we reached it, we
were stopped by a small party of Confederates on horseback. I
offered my passes. Striking a match, an officer read them, and after
a few questions, allowed us to go on. That was the only time the
passes were of use to us, for as soon as I parted with my disguise
they were, of course, worthless.
In order to make the best time possible, and avail ourselves of short
cuts and bridle paths, it was necessary to leave the buggy and
return to horseback. That we did at the earliest practical moment. As
soon as we came to a rough bit of road, after our first turn, Ned
drove the buggy to one side, and, knocking off a wheel, left it to its
fate. When I was again in my own clothes, we made the harness
and my disguise into several bundles, which Ned weighted and
dropped into the first creek we came to.
That done, we hurried on. The night had turned cloudy and dark
while we had been in the Confederate camp. It did not rain, but
before long we struck a place where it had very recently, and our
horses for a short distance were obliged to plough through slippery
clay. Frequently we would see the fires of some outpost, and often a
picket shot, sometimes startlingly near, would ring out on the murky
night.
Well as I knew the country, I finally made a false turn in the
confusing darkness, and approached the river when I thought we
were still several miles away from it and following its course.
Leaving Ned in safe hiding, I crept forward to reconnoiter. I made for
a rock overhanging the water, at the head of a bend in the river,
from the edge of which I hoped to be able to tell if the fires opposite
were repeated down the side I was on.
As I gained a sheltered place near the top and in the rear of the
rock, I heard a boat grate on the pebbles beneath, and two men
ascended to the very spot I had started for. I lay low behind the
scanty bushes, while they sat down near me. From what they said, I
gathered that they had crossed from the Rebel camp over the river
to investigate the bank up stream for some purpose, but not liking
the looks of something that had attracted their notice, they had
stopped there to decide what they should do.
I was too near to move away without them hearing me. I was
caught in a trap. Chaffing at a delay, when every moment was
precious, and fearing that Ned, alarmed at my protracted absence,
might come to look for me, I was obliged to crouch, motionless in
my hiding place, while the two men so near me idly discussed topics
relating to everything but the duty they were on. While I waited, the
clouds began to break away, and once or twice the moonlight shone
out full and strong, leaving me with little to shield me, had they
chanced to turn around.
Finally, after what seemed hours to me, one decided to go over for
re-enforcements and descended to the boat. Cautiously rising, as the
other advanced to the extreme edge of the rock, I saw that his back
was toward me and that he was intently watching the progress of
the boat, then in mid-stream.
It was possible then for me to have slipped away unnoticed, but I
was exasperated beyond endurance. An uncontrollable impulse
seized me. Even if I had been sure that the whole Confederate army
would have started to his rescue, I could not have helped pushing
that man into the water. Moving noiselessly behind him, with the end
of my revolver I gave him a sharp punch in the middle of the back.
Taken completely off his guard, without a word, but with a wild whirl
of arms and legs, he went straight down into the deep water
beneath. I have wondered hundreds of times since, what that man
thought was the matter with him. If he has lived to read this, he
knows now.
CHAPTER XIV.
I returned to where Ned was, and we began retracing our steps.
Although we made frequent attempts to get news, it was not until
nearly morning that I learned that our troops had advanced to a
point, nearer the place where I had made my way into the enemy's
camp, and, consequently, nearer where I was then, but to my left.
We immediately changed our route.
From the moment the order had fallen into my hands, my one desire
and aim was to get it where the information it contained, together
with what other I had gathered, could be put to instant use. Every
nerve throbbed with impatience. Every delay was intolerable. Yet
that entire ride back was a series of vexatious and dangerous delays.
I was beset on every side by dangers, which closed in on me at
every point where I tried to evade them. Every mile counted for four
in my eagerness to get on. I was obliged, time after time, to retrace
my steps and make long detours to avoid running into bodies of
skirmishers, to escape the vigilance of pickets, and to baffle the
pursuers on our tracks.
Twice that night we stood with our coats drawn tightly over our
horses' heads to keep them from making a sound to betray our
presence to the enemy, passing so closely below that by stooping,
we could have lifted the hats off of their heads with a ramrod.
Shortly after daybreak, as the first rays of of the sun showed over a
neighboring hill, I lay in a hollow log, while a man from the column
of passing soldiers sat on it to beat the dirt and stones from his
remnants of shoes. The dust from the inside of the log, loosened by
his pounding, choked me, until in my efforts to keep from coughing,
I bit through the sleeve of my coat, and left the print of my teeth on
my arm. About six hundred soldiers marched past me, as I watched
them from a crevice in the log.
Across the road and half way up the hill beyond I could see where
Ned crouched, keeping the horses back in the shelter of a low
thicket. Knowing exactly where to look for him, he stood out with
terrible distinctness to my abnormally keen sight, and I trembled
whenever I saw a soldier turn his head in that direction.
Even now, as I think it over, with all my increased experience and
knowledge of hair-breadth escapes, it seems simply incredible that
we ever got through. But get through we did.
By eight o'clock, exhausted to faintness from hard riding, lack of
food and loss of sleep, and with horses reeling from fatigue, we
turned out onto a road which in a few minutes took us beyond
danger. Loyal hands placed fresh horses at our disposal, and with
little loss of time, we were covering the last ten miles of our ride.
Soon the bit of paper, that "Lost Dispatch," which through all that
long and fearful night had been the elixir that nerved me to my
work, was in the hands of the proper officer, and I had
communicated to him the additional information I had gathered.
Both information and dispatch, without delay, were carried to the
Commander in Chief.
I only did my duty. My responsibility ended there. But looking back
now, it seems, as it did then, that better results should have been
obtained through a quick action on the intelligence gathered.
THE END.
*** END OF THE PROJECT GUTENBERG EBOOK THE LOST
DISPATCH ***
Updated editions will replace the previous one—the old editions will
be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.
START: FULL LICENSE
THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only be
used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright law
in the United States and you are located in the United States, we do
not claim a right to prevent you from copying, distributing,
performing, displaying or creating derivative works based on the
work as long as all references to Project Gutenberg are removed. Of
course, we hope that you will support the Project Gutenberg™
mission of promoting free access to electronic works by freely
sharing Project Gutenberg™ works in compliance with the terms of
this agreement for keeping the Project Gutenberg™ name associated
with the work. You can easily comply with the terms of this
agreement by keeping this work in the same format with its attached
full Project Gutenberg™ License when you share it without charge
with others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.
1.E. Unless you have removed all references to Project Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg” appears,
or with which the phrase “Project Gutenberg” is associated) is
accessed, displayed, performed, viewed, copied or distributed:
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this eBook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is derived
from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is posted
with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute this
electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the Project
Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™ works
unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or providing
access to or distributing Project Gutenberg™ electronic works
provided that:
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You provide a full refund of any money paid by a user who
notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full refund of
any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™
electronic work or group of works on different terms than are set
forth in this agreement, you must obtain permission in writing from
the Project Gutenberg Literary Archive Foundation, the manager of
the Project Gutenberg™ trademark. Contact the Foundation as set
forth in Section 3 below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on, transcribe
and proofread works not protected by U.S. copyright law in creating
the Project Gutenberg™ collection. Despite these efforts, Project
Gutenberg™ electronic works, and the medium on which they may
be stored, may contain “Defects,” such as, but not limited to,
incomplete, inaccurate or corrupt data, transcription errors, a
copyright or other intellectual property infringement, a defective or
damaged disk or other medium, a computer virus, or computer
codes that damage or cannot be read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for
the “Right of Replacement or Refund” described in paragraph 1.F.3,
the Project Gutenberg Literary Archive Foundation, the owner of the
Project Gutenberg™ trademark, and any other party distributing a
Project Gutenberg™ electronic work under this agreement, disclaim
all liability to you for damages, costs and expenses, including legal
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR
NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR
BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK
OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL
NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT,
CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF
YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you
discover a defect in this electronic work within 90 days of receiving
it, you can receive a refund of the money (if any) you paid for it by
sending a written explanation to the person you received the work
from. If you received the work on a physical medium, you must
return the medium with your written explanation. The person or
entity that provided you with the defective work may elect to provide
a replacement copy in lieu of a refund. If you received the work
electronically, the person or entity providing it to you may choose to
give you a second opportunity to receive the work electronically in
lieu of a refund. If the second copy is also defective, you may
demand a refund in writing without further opportunities to fix the
problem.
1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.
1.F.5. Some states do not allow disclaimers of certain implied
warranties or the exclusion or limitation of certain types of damages.
If any disclaimer or limitation set forth in this agreement violates the
law of the state applicable to this agreement, the agreement shall be
interpreted to make the maximum disclaimer or limitation permitted
by the applicable state law. The invalidity or unenforceability of any
provision of this agreement shall not void the remaining provisions.
1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation,
the trademark owner, any agent or employee of the Foundation,
anyone providing copies of Project Gutenberg™ electronic works in
accordance with this agreement, and any volunteers associated with
the production, promotion and distribution of Project Gutenberg™
electronic works, harmless from all liability, costs and expenses,
including legal fees, that arise directly or indirectly from any of the
following which you do or cause to occur: (a) distribution of this or
any Project Gutenberg™ work, (b) alteration, modification, or
additions or deletions to any Project Gutenberg™ work, and (c) any
Defect you cause.
Section 2. Information about the Mission
of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new computers.
It exists because of the efforts of hundreds of volunteers and
donations from people in all walks of life.
Volunteers and financial support to provide volunteers with the
assistance they need are critical to reaching Project Gutenberg™’s
goals and ensuring that the Project Gutenberg™ collection will
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.
Section 3. Information about the Project
Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.
The Foundation’s business office is located at 809 North 1500 West,
Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.
The Foundation is committed to complying with the laws regulating
charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.
While we cannot and do not solicit contributions from states where
we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.
International donations are gratefully accepted, but we cannot make
any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.
Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.
Section 5. General Information About
Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
This website includes information about Project Gutenberg™,
including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

PDF
Core Java Volume I Fundamentals 12th Horstmann Cay
PDF
Core Java Vol 1 2 For The Impatient And Effective Pack 12th Ed Cay S Horstmann
PDF
Learning Java 4th Edition Patrick Niemeyer Daniel Leuck
PDF
Download full ebook of Java Cookbook Ian F Darwin Darwin Ian F instant downlo...
PDF
Learning Java An Introduction to Real World Programming with Java Marc Loy
PDF
Java Complete Reference Fifth Edition
PDF
Learning Java An Introduction to Real World Programming with Java Marc Loy
PDF
Javatech An Introduction To Scientific And Technical Computing With Java Clar...
Core Java Volume I Fundamentals 12th Horstmann Cay
Core Java Vol 1 2 For The Impatient And Effective Pack 12th Ed Cay S Horstmann
Learning Java 4th Edition Patrick Niemeyer Daniel Leuck
Download full ebook of Java Cookbook Ian F Darwin Darwin Ian F instant downlo...
Learning Java An Introduction to Real World Programming with Java Marc Loy
Java Complete Reference Fifth Edition
Learning Java An Introduction to Real World Programming with Java Marc Loy
Javatech An Introduction To Scientific And Technical Computing With Java Clar...

Similar to Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann (20)

PDF
Objectoriented Programming And Java 2nd Ed Danny C C Poo Derek Beng Kee Kiong...
PDF
[FREE PDF sample] Object Oriented Programming and Java Second Edition Danny P...
PDF
Core Java An Integrated Approach 2nd R Nageswara Rao
PDF
Programming For Corpus Linguistics How To Do Text Analysis With Java Oliver M...
PPT
Introduction to Java(basic understanding).ppt
PDF
JDK 1 4 Tutorial 1 (no book cover) Edition Gregory Travis
PPT
Introduction to Software Development
PPT
PDF
Essential Java For Scientists And Engineers 1st Brian D Hahn
PDF
Java quickref
PDF
(eTextbook PDF) for Starting Out with Java: From Control Structures through O...
PDF
(eBook PDF) Introduction to Programming with Java: A Problem Solving Approach...
PDF
Core Java Training in Bangalore | Best Core Java Class in Bangalore
PPTX
Introduction to java
PDF
A Comprehensive Introduction to Object-Oriented Programming with Java.pdf
PDF
(eBook PDF) Introduction to Programming with Java: A Problem Solving Approach...
PDF
What`s new in Java 7
PDF
(eBook PDF) Starting Out with Java: From Control Structures through Objects, ...
PPT
Java SpringMVC SpringBOOT (Divergent).ppt
PDF
Java quick reference v2
Objectoriented Programming And Java 2nd Ed Danny C C Poo Derek Beng Kee Kiong...
[FREE PDF sample] Object Oriented Programming and Java Second Edition Danny P...
Core Java An Integrated Approach 2nd R Nageswara Rao
Programming For Corpus Linguistics How To Do Text Analysis With Java Oliver M...
Introduction to Java(basic understanding).ppt
JDK 1 4 Tutorial 1 (no book cover) Edition Gregory Travis
Introduction to Software Development
Essential Java For Scientists And Engineers 1st Brian D Hahn
Java quickref
(eTextbook PDF) for Starting Out with Java: From Control Structures through O...
(eBook PDF) Introduction to Programming with Java: A Problem Solving Approach...
Core Java Training in Bangalore | Best Core Java Class in Bangalore
Introduction to java
A Comprehensive Introduction to Object-Oriented Programming with Java.pdf
(eBook PDF) Introduction to Programming with Java: A Problem Solving Approach...
What`s new in Java 7
(eBook PDF) Starting Out with Java: From Control Structures through Objects, ...
Java SpringMVC SpringBOOT (Divergent).ppt
Java quick reference v2
Ad

Recently uploaded (20)

PPTX
Final Presentation General Medicine 03-08-2024.pptx
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PDF
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
PPTX
Lesson notes of climatology university.
PPTX
Cell Types and Its function , kingdom of life
PPTX
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
PDF
grade 11-chemistry_fetena_net_5883.pdf teacher guide for all student
PDF
Supply Chain Operations Speaking Notes -ICLT Program
PPTX
Cell Structure & Organelles in detailed.
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
PPH.pptx obstetrics and gynecology in nursing
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PDF
Basic Mud Logging Guide for educational purpose
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
TR - Agricultural Crops Production NC III.pdf
PDF
Microbial disease of the cardiovascular and lymphatic systems
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PPTX
Institutional Correction lecture only . . .
Final Presentation General Medicine 03-08-2024.pptx
Renaissance Architecture: A Journey from Faith to Humanism
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
Lesson notes of climatology university.
Cell Types and Its function , kingdom of life
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
grade 11-chemistry_fetena_net_5883.pdf teacher guide for all student
Supply Chain Operations Speaking Notes -ICLT Program
Cell Structure & Organelles in detailed.
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPH.pptx obstetrics and gynecology in nursing
2.FourierTransform-ShortQuestionswithAnswers.pdf
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Basic Mud Logging Guide for educational purpose
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
TR - Agricultural Crops Production NC III.pdf
Microbial disease of the cardiovascular and lymphatic systems
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
human mycosis Human fungal infections are called human mycosis..pptx
Institutional Correction lecture only . . .
Ad

Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann

  • 1. Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann download https://ebookbell.com/product/core-java-vol-iiadvanced- features-12th-edition-cay-s-horstmann-49554648 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Core Java Vol Iiadvanced Features 12th Edition Cay S Horstmann https://ebookbell.com/product/core-java-vol-iiadvanced-features-12th- edition-cay-s-horstmann-38321494 Core Java Volume Ii Advanced Features 11th Vol Ii Cay Horstmann https://ebookbell.com/product/core-java-volume-ii-advanced- features-11th-vol-ii-cay-horstmann-9992752 Core Java Vol 1 2 For The Impatient And Effective Pack 12th Ed Cay S Horstmann https://ebookbell.com/product/core-java-vol-1-2-for-the-impatient-and- effective-pack-12th-ed-cay-s-horstmann-50687482 Core Java Volume I Fundamentals 12th Horstmann Cay https://ebookbell.com/product/core-java-volume-i-fundamentals-12th- horstmann-cay-46173296
  • 3. Core Java Volume Ii Advanced Features 12th Cay S Horstmann https://ebookbell.com/product/core-java-volume-ii-advanced- features-12th-cay-s-horstmann-46173298 Core Java For The Impatient 3rd Edition Cay Horstmann https://ebookbell.com/product/core-java-for-the-impatient-3rd-edition- cay-horstmann-48456364 Core Java Interview Questions Youll Most Likely Be Asked Job Interview Questions Series 2nd Edition Vibrant Publishers https://ebookbell.com/product/core-java-interview-questions-youll- most-likely-be-asked-job-interview-questions-series-2nd-edition- vibrant-publishers-49183978 Core Java Made Simple Som Prakash Rai https://ebookbell.com/product/core-java-made-simple-som-prakash- rai-49422914 Core Java Volume Ifundamentals Cay S Horstmann https://ebookbell.com/product/core-java-volume-ifundamentals-cay-s- horstmann-49541448
  • 6. Core Java, Vol. II-Advanced Features 12th Edition Cay S. Horstmann
  • 7. Contents Preface Acknowledgments Chapter 1: Streams Chapter 2: Input and Output Chapter 3: XML Chapter 4: Networking Chapter 5: Database Programming Chapter 6: The Date and Time API Chapter 7: Internationalization Chapter 8: Scripting, Compiling, and Annotation Processing Chapter 9: The Java Platform Module System Chapter 10: Security Chapter 11: Advanced Swing and Graphics Chapter 12: Native Methods
  • 8. Table of Contents Preface Acknowledgments Chapter 1: Streams 1.1 From Iterating to Stream Operations 1.2 Stream Creation 1.3 The filter, map, and flatMap Methods 1.4 Extracting Substreams and Combining Streams 1.5 Other Stream Transformations 1.6 Simple Reductions 1.7 The Optional Type 1.7.1 Getting an Optional Value 1.7.2 Consuming an Optional Value 1.7.3 Pipelining Optional Values 1.7.4 How Not to Work with Optional Values 1.7.5 Creating Optional Values 1.7.6 Composing Optional Value Functions with flatMap 1.7.7 Turning an Optional into a Stream 1.8 Collecting Results 1.9 Collecting into Maps 1.10 Grouping and Partitioning
  • 9. 1.11 Downstream Collectors 1.12 Reduction Operations 1.13 Primitive Type Streams 1.14 Parallel Streams Chapter 2: Input and Output 2.1 Input/Output Streams 2.1.1 Reading and Writing Bytes 2.1.2 The Complete Stream Zoo 2.1.3 Combining Input/Output Stream Filters 2.1.4 Text Input and Output 2.1.5 How to Write Text Output 2.1.6 How to Read Text Input 2.1.7 Saving Objects in Text Format 2.1.8 Character Encodings 2.2 Reading and Writing Binary Data 2.2.1 The DataInput and DataOutput interfaces 2.2.2 Random-Access Files 2.2.3 ZIP Archives 2.3 Object Input/Output Streams and Serialization 2.3.1 Saving and Loading Serializable Objects 2.3.2 Understanding the Object Serialization File Format 2.3.3 Modifying the Default Serialization Mechanism 2.3.4 The readResolve and writeReplace methods 2.3.5 Versioning 2.3.6 Using Serialization for Cloning 2.3.7 Deserialization and Security 2.4 Working with Files 2.4.1 Paths 2.4.2 Reading and Writing Files 2.4.3 Creating Files and Directories 2.4.4 Copying, Moving, and Deleting Files
  • 10. 2.4.5 Getting File Information 2.4.6 Visiting Directory Entries 2.4.7 Using Directory Streams 2.4.8 ZIP File Systems 2.5 Memory-Mapped Files 2.5.1 Memory-Mapped File Performance 2.5.2 The Buffer Data Structure 2.6 File Locking 2.7 Regular Expressions 2.7.1 The Regular Expression Syntax 2.7.2 Matching an Entire String 2.7.3 Finding All Matches in a String 2.7.4 Groups 2.7.5 Splitting along Delimiters 2.7.6 Replacing Matches 2.7.7 Flags Chapter 3: XML 3.1 Introducing XML 3.2 The Structure of an XML Document 3.3 Parsing an XML Document 3.4 Validating XML Documents 3.4.1 Document Type Definitions 3.4.2 XML Schema 3.4.3 A Practical Example 3.5 Locating Information with XPath 3.6 Using Namespaces 3.7 Streaming Parsers 3.7.1 Using the SAX Parser 3.7.2 Using the StAX Parser 3.8 Generating XML Documents 3.8.1 Documents without Namespaces
  • 11. 3.8.2 Documents with Namespaces 3.8.3 Writing Documents 3.8.4 Writing an XML Document with StAX 3.8.5 An Example: Generating an SVG File 3.9 XSL Transformations Chapter 4: Networking 4.1 Connecting to a Server 4.1.1 Using Telnet 4.1.2 Connecting to a Server with Java 4.1.3 Socket Timeouts 4.1.4 Internet Addresses 4.2 Implementing Servers 4.2.1 Server Sockets 4.2.2 Serving Multiple Clients 4.2.3 Half-Close 4.2.4 Interruptible Sockets 4.3 Getting Web Data 4.3.1 URLs and URIs 4.3.2 Using a URLConnection to Retrieve Information 4.3.3 Posting Form Data 4.4 The HTTP Client 4.4.1 The HttpClient Class 4.4.2 The HttpRequest class and Body Publishers 4.4.3 The HttpResponse Interface and Body Handlers 4.4.4 Asynchronous Processing 4.5 Sending E-Mail Chapter 5: Database Programming 5.1 The Design of JDBC 5.1.1 JDBC Driver Types 5.1.2 Typical Uses of JDBC
  • 12. 5.2 The Structured Query Language 5.3 JDBC Configuration 5.3.1 Database URLs 5.3.2 Driver JAR Files 5.3.3 Starting the Database 5.3.4 Registering the Driver Class 5.3.5 Connecting to the Database 5.4 Working with JDBC Statements 5.4.1 Executing SQL Statements 5.4.2 Managing Connections, Statements, and Result Sets 5.4.3 Analyzing SQL Exceptions 5.4.4 Populating a Database 5.5 Query Execution 5.5.1 Prepared Statements 5.5.2 Reading and Writing LOBs 5.5.3 SQL Escapes 5.5.4 Multiple Results 5.5.5 Retrieving Autogenerated Keys 5.6 Scrollable and Updatable Result Sets 5.6.1 Scrollable Result Sets 5.6.2 Updatable Result Sets 5.7 Row Sets 5.7.1 Constructing Row Sets 5.7.2 Cached Row Sets 5.8 Metadata 5.9 Transactions 5.9.1 Programming Transactions with JDBC 5.9.2 Save Points 5.9.3 Batch Updates 5.9.4 Advanced SQL Types 5.10 Connection Management in Web and Enterprise Applications
  • 13. Chapter 6: The Date and Time API 6.1 The Time Line 6.2 Local Dates 6.3 Date Adjusters 6.4 Local Time 6.5 Zoned Time 6.6 Formatting and Parsing 6.7 Interoperating with Legacy Code Chapter 7: Internationalization 7.1 Locales 7.1.1 Why Locales? 7.1.2 Specifying Locales 7.1.3 The Default Locale 7.1.4 Display Names 7.2 Number Formats 7.2.1 Formatting Numeric Values 7.2.2 The DecimalFormat Class 7.2.3 Currencies 7.3 Date and Time 7.4 Collation and Normalization 7.5 Message Formatting 7.5.1 Formatting Numbers and Dates 7.5.2 Choice Formats 7.6 Text Input and Output 7.6.1 Text Files 7.6.2 Line Endings 7.6.3 The Console 7.6.4 Log Files 7.6.5 The UTF-8 Byte Order Mark 7.6.6 Character Encoding of Source Files
  • 14. 7.7 Resource Bundles 7.7.1 Locating Resource Bundles 7.7.2 Property Files 7.7.3 Bundle Classes 7.8 A Complete Example Chapter 8: Scripting, Compiling, and Annotation Processing 8.1 Scripting for the Java Platform 8.1.1 Getting a Scripting Engine 8.1.2 Script Evaluation and Bindings 8.1.3 Redirecting Input and Output 8.1.4 Calling Scripting Functions and Methods 8.1.5 Compiling a Script 8.1.6 An Example: Scripting GUI Events 8.2 The Compiler API 8.2.1 Invoking the Compiler 8.2.2 Launching a Compilation Task 8.2.3 Capturing Diagnostics 8.2.4 Reading Source Files from Memory 8.2.5 Writing Byte Codes to Memory 8.2.6 An Example: Dynamic Java Code Generation 8.3 Using Annotations 8.3.1 An Introduction into Annotations 8.3.2 An Example: Annotating Event Handlers 8.4 Annotation Syntax 8.4.1 Annotation Interfaces 8.4.2 Annotations 8.4.3 Annotating Declarations 8.4.4 Annotating Type Uses 8.4.5 Annotating this 8.5 Standard Annotations 8.5.1 Annotations for Compilation
  • 15. 8.5.2 Meta-Annotations 8.6 Source-Level Annotation Processing 8.6.1 Annotation Processors 8.6.2 The Language Model API 8.6.3 Using Annotations to Generate Source Code 8.7 Bytecode Engineering 8.7.1 Modifying Class Files 8.7.2 Modifying Bytecodes at Load Time Chapter 9: The Java Platform Module System 9.1 The Module Concept 9.2 Naming Modules 9.3 The Modular “Hello, World!” Program 9.4 Requiring Modules 9.5 Exporting Packages 9.6 Modular JARs 9.7 Modules and Reflective Access 9.8 Automatic Modules 9.9 The Unnamed Module 9.10 Command-Line Flags for Migration 9.11 Transitive and Static Requirements 9.12 Qualified Exporting and Opening 9.13 Service Loading 9.14 Tools for Working with Modules Chapter 10: Security 10.1 Class Loaders 10.1.1 The Class-Loading Process 10.1.2 The Class Loader Hierarchy 10.1.3 Using Class Loaders as Namespaces 10.1.4 Writing Your Own Class Loader 10.1.5 Bytecode Verification
  • 16. 10.2 User Authentication 10.2.1 The JAAS Framework 10.2.2 JAAS Login Modules 10.3 Digital Signatures 10.3.1 Message Digests 10.3.2 Message Signing 10.3.3 Verifying a Signature 10.3.4 The Authentication Problem 10.3.5 Certificate Signing 10.3.6 Certificate Requests 10.3.7 Code Signing 10.4 Encryption 10.4.1 Symmetric Ciphers 10.4.2 Key Generation 10.4.3 Cipher Streams 10.4.4 Public Key Ciphers Chapter 11: Advanced Swing and Graphics 11.1 Tables 11.1.1 A Simple Table 11.1.2 Table Models 11.1.3 Working with Rows and Columns 11.1.3.1 Column Classes 11.1.3.2 Accessing Table Columns 11.1.3.3 Resizing Columns 11.1.3.4 Resizing Rows 11.1.3.5 Selecting Rows, Columns, and Cells 11.1.3.6 Sorting Rows 11.1.3.7 Filtering Rows 11.1.3.8 Hiding and Displaying Columns 11.1.4 Cell Rendering and Editing 11.1.4.1 Rendering Cells
  • 17. 11.1.4.2 Rendering the Header 11.1.4.3 Editing Cells 11.1.4.4 Custom Editors 11.2 Trees 11.2.1 Simple Trees 11.2.1.1 Editing Trees and Tree Paths 11.2.2 Node Enumeration 11.2.3 Rendering Nodes 11.2.4 Listening to Tree Events 11.2.5 Custom Tree Models 11.3 Advanced AWT 11.3.1 The Rendering Pipeline 11.3.2 Shapes 11.3.2.1 The Shape Class Hierarchy 11.3.2.2 Using the Shape Classes 11.3.3 Areas 11.3.4 Strokes 11.3.5 Paint 11.3.6 Coordinate Transformations 11.3.7 Clipping 11.3.8 Transparency and Composition 11.4 Raster Images 11.4.1 Readers and Writers for Images 11.4.1.1 Obtaining Readers and Writers for Image File Types 11.4.1.2 Reading and Writing Files with Multiple Images 11.4.2 Image Manipulation 11.4.2.1 Constructing Raster Images 11.4.2.2 Filtering Images 11.5 Printing 11.5.1 Graphics Printing 11.5.2 Multiple-Page Printing 11.5.3 Print Services
  • 18. 11.5.4 Stream Print Services 11.5.5 Printing Attributes Chapter 12: Native Methods 12.1 Calling a C Function from a Java Program 12.2 Numeric Parameters and Return Values 12.3 String Parameters 12.4 Accessing Fields 12.4.1 Accessing Instance Fields 12.4.2 Accessing Static Fields 12.5 Encoding Signatures 12.6 Calling Java Methods 12.6.1 Instance Methods 12.6.2 Static Methods 12.6.3 Constructors 12.6.4 Alternative Method Invocations 12.7 Accessing Array Elements 12.8 Handling Errors 12.9 Using the Invocation API 12.10 A Complete Example: Accessing the Windows Registry 12.10.1 Overview of the Windows Registry 12.10.2 A Java Platform Interface for Accessing the Registry 12.10.3 Implementation of Registry Access Functions as Native Methods 12.11 Foreign Functions: A Glimpse into the Future
  • 19. Preface To the Reader The book you have in your hands is the second volume of the twelfth edition of Core Java, fully updated for Java SE 17. The first volume covers the essential features of the language; this volume deals with the advanced topics that a programmer needs to know for professional software development. Thus, as with the first volume and the previous editions of this book, we are still targeting programmers who want to put Java technology to work in real projects. As is the case with any book, errors and inaccuracies are inevitable. Should you find any in this book, we would very much like to hear about them. Of course, we would prefer to hear about them only once. For this reason, we have put up a web site at http://horstmann.com/corejava with a FAQ, bug fixes, and workarounds. Strategically placed at the end of the bug report web page (to encourage you to read the previous reports) is a form that you can use to report bugs or problems and to send suggestions for improvements for future editions. About This Book
  • 20. The chapters in this book are, for the most part, independent of each other. You should be able to delve into whatever topic interests you the most and read the chapters in any order. In Chapter 1, you will learn all about the Java stream library that brings a modern flavor to processing data, by specifying what you want without describing in detail how the result should be obtained. This allows the stream library to focus on an optimal evaluation strategy, which is particularly advantageous for optimizing concurrent computations. The topic of Chapter 2 is input and output handling (I/O). In Java, all input and output is handled through input/output streams. These streams (not to be confused with those in Chapter 1) let you deal, in a uniform manner, with communications among various sources of data, such as files, network connections, or memory blocks. We include detailed coverage of the reader and writer classes that make it easy to deal with Unicode. We show you what goes on under the hood when you use the object serialization mechanism, which makes saving and loading objects easy and convenient. We then move on to regular expressions and working with files and paths. Throughout this chapter, you will find welcome enhancements in recent Java versions. Chapter 3 covers XML. We show you how to parse XML files, how to generate XML, and how to use XSL transformations. As a useful example, we show you how to specify the layout of a Swing form in XML. We also discuss the XPath API, which makes finding needles in XML haystacks much easier. Chapter 4 covers the networking API. Java makes it phenomenally easy to do complex network programming. We show you how to make network connections to servers, how to implement your own servers, and how to make HTTP connections. This chapter includes coverage of the new HTTP client. Chapter 5 covers database programming. The focus is on JDBC, the Java database connectivity API that lets Java programs connect to relational databases. We show you how to write useful programs to handle realistic
  • 21. database chores, using a core subset of the JDBC API. (A complete treatment of the JDBC API would require a book almost as big as this one.) Java had two prior attempts at libraries for handling date and time. The third one was the charm in Java 8. In Chapter 6, you will learn how to deal with the complexities of calendars and time zones, using the new date and time library. Chapter 7 discusses a feature that we believe can only grow in importance: internationalization. The Java programming language is one of the few languages designed from the start to handle Unicode, but the internationalization support on the Java platform goes much further. As a result, you can internationalize Java applications so that they cross not only platforms but country boundaries as well. For example, we show you how to write a retirement calculator that uses either English, German, or Chinese languages. Chapter 8 discusses three techniques for processing code. The scripting and compiler APIs allow your program to call code in scripting languages such as JavaScript or Groovy, and to compile Java code. Annotations allow you to add arbitrary information (sometimes called metadata) to a Java program. We show you how annotation processors can harvest these annotations at the source or class file level, and how annotations can be used to influence the behavior of classes at runtime. Annotations are only useful with tools, and we hope that our discussion will help you select useful annotation processing tools for your needs. In Chapter 9, you will learn about the Java Platform Module System that was introduced in Java 9 to facilitate an orderly evolution of the Java platform and core libraries. This module system provides encapsulation for packages and a mechanism for describing module requirements. You will learn the properties of modules so that you can decide whether to use them in your own applications. Even if you decide not to, you need to know the new rules so that you can interact with the Java platform and other modularized libraries. Chapter 10 takes up the Java security model, user authentication, and the cryptographic functions in the Java security library. You will learn about
  • 22. important features as message and code signing, authorization and authentication, and encryption. We conclude with examples that use the AES and RSA encryption algorithms. Chapter 11 contains all the Swing material that didn’t make it into Volume I, especially the important but complex tree and table components. We also cover the Java 2D API, which you can use to create realistic drawings and special effects. Of course, not many programmers need to program Swing user interfaces these days, so we pay particular attention to features that are useful for images that can be generated on a server. Chapter 12 takes up native methods, which let you call methods written for a specific machine such as the Microsoft Windows API. Obviously, this feature is controversial: Use native methods, and the cross-platform nature of Java vanishes. Nonetheless, every serious programmer writing Java applications for specific platforms needs to know these techniques. At times, you need to turn to the operating system’s API for your target platform when you interact with a device or service that is not supported by Java. We illustrate this by showing you how to access the registry API in Windows from a Java program. As always, all chapters have been completely revised for the latest version of Java. Outdated material has been removed, and the new APIs up to Java 17 are covered in detail. Conventions As is common in many computer books, we use monospace type to represent computer code. Note Notes are tagged with “note” icons that look like this.
  • 23. Tip Tips are tagged with “tip” icons that look like this. Caution When there is danger ahead, we warn you with a “caution” icon. C++ Note: There are a number of C++ notes that explain the difference between the Java programming language and C++. You can skip them if you aren’t interested in C++. Java comes with a large programming library, or Application Programming Interface (API). When using an API call for the first time, we add a short summary description at the end of the section. These descriptions are a bit more informal but, we hope, also a little more informative than those in the official online API documentation. The names of interfaces are in italics, just like in the official documentation. The number after a class, interface, or method name is the JDK version in which the feature was introduced. Application Programming Interface 1.2 Programs whose source code is included in the companion code for this book are listed as examples, for instance Listing 1.1 ScriptTest.java
  • 24. You can download the companion code from http://horstmann.com/corejava. Register your copy of Core Java, Volume II—Advanced Features, Eleventh Edition, on the InformIT site for convenient access to updates and/or corrections as they become available. To start the registration process, go to informit.com/register and log in or create an account. Enter the product ISBN (9780135166314) and click Submit. Look on the Registered Products tab for an Access Bonus Content link next to this product, and follow that link to access any available bonus materials. If you would like to be notified of exclusive offers on new editions and updates, please check the box to receive email from us.
  • 25. Acknowledgments Writing a book is always a monumental effort, and rewriting doesn’t seem to be much easier, especially with such a rapid rate of change in Java technology. Making a book a reality takes many dedicated people, and it is my great pleasure to acknowledge the contributions of the entire Core Java team. A large number of individuals at Pearson provided valuable assistance, but they managed to stay behind the scenes. I’d like them all to know how much I appreciate their efforts. As always, my warm thanks go to my editor, Greg Doench, for steering the book through the writing and production process, and for allowing me to be blissfully unaware of the existence of all those folks behind the scenes. I am very grateful to Julie Nahil for production support, and to Dmitry Kirsanov and Alina Kirsanova for copyediting and typesetting the manuscript. Thanks to the many readers of earlier editions who reported embarrassing errors and made lots of thoughtful suggestions for improvement. I am particularly grateful to the excellent reviewing team that went over the manuscript with an amazing eye for detail and saved me from many more embarrassing errors. Reviewers of this and earlier editions include Chuck Allison (Utah Valley University), Lance Andersen (Oracle), Gail Anderson (Anderson Software Group), Paul Anderson (Anderson Software Group), Alec Beaton (IBM), Cliff Berg, Andrew Binstock (Oracle), Joshua Bloch, David Brown, Corky
  • 26. Cartwright, Frank Cohen (PushToTest), Chris Crane (devXsolution), Dr. Nicholas J. De Lillo (Manhattan College), Rakesh Dhoopar (Oracle), Robert Evans (Senior Staff, The Johns Hopkins University Applied Physics Lab), David Geary (Clarity Training), Jim Gish (Oracle), Brian Goetz (Oracle), Angela Gordon, Dan Gordon (Electric Cloud), Rob Gordon, John Gray (University of Hartford), Cameron Gregory (olabs.com), Steve Haines, Marty Hall (coreservlets.com, Inc.), Vincent Hardy (Adobe Systems), Dan Harkey (San Jose State University), William Higgins (IBM), Marc Hoffmann (mtrail), Vladimir Ivanovic (PointBase), Jerry Jackson (CA Technologies), Heinz Kabutz (Java Specialists), Stepan V. Kalinin (I- Teco/Servionica LTD), Tim Kimmet (Walmart), Chris Laffra, Charlie Lai (Apple), Angelika Langer, Jeff Langr (Langr Software Solutions), Doug Langston, Hang Lau (McGill University), Mark Lawrence, Doug Lea (SUNY Oswego), Gregory Longshore, Bob Lynch (Lynch Associates), Philip Milne (consultant), Mark Morrissey (The Oregon Graduate Institute), Mahesh Neelakanta (Florida Atlantic University), José Paumard (Oracle), Hao Pham, Paul Philion, Blake Ragsdell, Ylber Ramadani (Ryerson University), Stuart Reges (University of Arizona), Simon Ritter (Azul Systems), Rich Rosen (Interactive Data Corporation), Peter Sanders (ESSI University, Nice, France), Dr. Paul Sanghera (San Jose State University and Brooks College), Paul Sevinc (Teamup AG), Devang Shah (Sun Microsystems), Yoshiki Shibata, Richard Slywczak (NASA/Glenn Research Center), Bradley A. Smith, Steven Stelting (Oracle), Christopher Taylor, Luke Taylor (Valtech), George Thiruvathukal, Kim Topley (StreamingEdge), Janet Traub, Paul Tyma (consultant), Christian Ullenboom, Peter van der Linden, Burt Walsh, Joe Wang (Oracle), Dan Xu (Oracle), and John Zavgren (Oracle). Cay Horstmann Berlin, Germany December 2021
  • 27. Chapter 1: Streams In this chapter • 1.1 From Iterating to Stream Operations • 1.2 Stream Creation • 1.3 The filter, map, and flatMap Methods • 1.4 Extracting Substreams and Combining Streams • 1.5 Other Stream Transformations • 1.6 Simple Reductions • 1.7 The Optional Type • 1.8 Collecting Results • 1.9 Collecting into Maps • 1.10 Grouping and Partitioning • 1.11 Downstream Collectors • 1.12 Reduction Operations • 1.13 Primitive Type Streams • 1.14 Parallel Streams Compared to collections, streams provide a view of data that lets you specify computations at a higher conceptual level. With a stream, you
  • 28. specify what you want to have done, not how to do it. You leave the scheduling of operations to the implementation. For example, suppose you want to compute the average of a certain property. You specify the source of data and the property, and the stream library can then optimize the computation, for example by using multiple threads for computing sums and counts and combining the results. In this chapter, you will learn how to use the Java stream library, which was introduced in Java 8, to process collections in a “what, not how” style. 1.1 From Iterating to Stream Operations When you process a collection, you usually iterate over its elements and do some work with each of them. For example, suppose we want to count all long words in a book. First, let’s put them into a list: var contents = Files.readString(Path.of("alice.txt"))); // Read file into string List<String> words = List.of(contents.split("PL+")); // Split into words; nonletters are delimiters Now we are ready to iterate: int count = 0; for (String w : words) { if (w.length() > 12) count++; } With streams, the same operation looks like this:
  • 29. long count = words.stream() .filter(w -> w.length() > 12) .count(); Now you don’t have to scan the loop for evidence of filtering and counting. The method names tell you right away what the code intends to do. Moreover, where the loop prescribes the order of operations in complete detail, a stream is able to schedule the operations any way it wants, as long as the result is correct. Simply changing stream to parallelStream allows the stream library to do the filtering and counting in parallel. long count = words.parallelStream() .filter(w -> w.length() > 12) .count(); Streams follow the “what, not how” principle. In our stream example, we describe what needs to be done: get the long words and count them. We don’t specify in which order, or in which thread, this should happen. In contrast, the loop at the beginning of this section specifies exactly how the computation should work, and thereby forgoes any chances of optimization. A stream seems superficially similar to a collection, allowing you to transform and retrieve data. But there are significant differences: 1. A stream does not store its elements. They may be stored in an underlying collection or generated on demand. 2. Stream operations don’t mutate their source. For example, the filter method does not remove elements from a stream but yields a new stream in which they are not present. 3. Stream operations are lazy when possible. This means they are not executed until their result is needed. For example, if you only ask for the first five long words instead of all, the filter method will stop filtering after the fifth match. As a consequence, you can even have infinite streams!
  • 30. Let us have another look at the example. The stream and parallelStream methods yield a stream for the words list. The filter method returns another stream that contains only the words of length greater than twelve. The count method reduces that stream to a result. This workflow is typical when you work with streams. You set up a pipeline of operations in three stages: 1. Create a stream. 2. Specify intermediate operations for transforming the initial stream into others, possibly in multiple steps. 3. Apply a terminal operation to produce a result. This operation forces the execution of the lazy operations that precede it. Afterwards, the stream can no longer be used. In the example in Listing 1.1, the stream is created with the stream or parallelStream method. The filter method transforms it, and count is the terminal operation. In the next section, you will see how to create a stream. The subsequent three sections deal with stream transformations. They are followed by five sections on terminal operations. Listing 1.1 streams/CountLongWords.java 1 package streams; 2 3 import java.io.*; 4 import java.nio.file.*; 5 import java.util.*; 6 7 /** 8 * @version 1.02 2019-08-28 9 * @author Cay Horstmann 10 */
  • 31. 11 public class CountLongWords 12 { 13 public static void main(String[] args) throws IOException 14 { 15 var contents = Files.readString( 16 Path.of("../gutenberg/alice30.txt")); 17 List<String> words = List.of(contents.split("PL+")); 18 19 long count = 0; 20 for (String w : words) 21 { 22 if (w.length() > 12) count++; 23 } 24 System.out.println(count); 25 26 count = words.stream().filter(w -> w.length() > 12).count(); 27 System.out.println(count); 28 29 count = words.parallelStream().filter(w -> w.length() > 12).count(); 30 System.out.println(count); 31 } 32 } java.util.stream.Stream<T> 8 • Stream<T> filter(Predicate<? super T> p) yields a stream containing all elements of this stream fulfilling p. • long count() yields the number of elements of this stream. This is a terminal operation. java.util.Collection<E> 1.2
  • 32. • default Stream<E> stream() • default Stream<E> parallelStream() yield a sequential or parallel stream of the elements in this collection. 1.2 Stream Creation You have already seen that you can turn any collection into a stream with the stream method of the Collection interface. If you have an array, use the static Stream.of method instead. Stream<String> words = Stream.of(contents.split("PL+")); // split returns a String[] array The of method has a varargs parameter, so you can construct a stream from any number of arguments: Stream<String> song = Stream.of("gently", "down", "the", "stream"); Use Arrays.stream(array, from, to) to make a stream from a part of an array. To make a stream with no elements, use the static Stream.empty method: Stream<String> silence = Stream.empty(); // Generic type <String> is inferred; same as Stream. <String>empty()
  • 33. The Stream interface has two static methods for making infinite streams. The generate method takes a function with no arguments (or, technically, an object of the Supplier<T> interface). Whenever a stream value is needed, that function is called to produce a value. You can get a stream of constant values as Stream<String> echos = Stream.generate(() -> "Echo"); or a stream of random numbers as Stream<Double> randoms = Stream.generate(Math::random); To produce sequences such as 0 1 2 3 . . ., use the iterate method instead. It takes a “seed” value and a function (technically, a UnaryOperator<T>) and repeatedly applies the function to the previous result. For example, Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)); The first element in the sequence is the seed BigInteger.ZERO. The second element is f(seed) which yields 1 (as a big integer). The next element is f(f(seed)) which yields 2, and so on. To produce a finite stream instead, add a predicate that specifies when the iteration should finish: var limit = new BigInteger("10000000"); Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.compareTo(limit) < 0, n -> n.add(BigInteger.ONE)); As soon as the predicate rejects an iteratively generated value, the stream ends.
  • 34. Finally, the Stream.ofNullable method makes a really short stream from an object. The stream has length 0 if the object is null or length 1 otherwise, containing just the object. This is mostly useful in conjunction with flatMap—see Section 1.7.7, “Turning an Optional into a Stream,” on p. 23 for an example. Note A number of methods in the Java API yield streams. For example, the String class has a lines method that yields a stream of the lines contained in the string: Stream<String> greetings = "HellonGuten TagnBonjour".lines() The Pattern class has a method splitAsStream that splits a CharSequence by a regular expression. You can use the following statement to split a string into words: Stream<String> words = Pattern.compile("PL+").splitAsStream(contents); The Scanner.tokens method yields a stream of tokens of a scanner. Another way to get a stream of words from a string is Stream<String> words = new Scanner(contents).tokens(); The static Files.lines method returns a Stream of all lines in a file: try (Stream<String> lines = Files.lines(path)) { Process lines } To view the contents of one of the streams introduced in this section, use the toList method, which collects the stream’s elements in a list. Like count, toList is a terminal operation. If the stream is infinite, first truncate it with the limit method:
  • 35. System.out.println(Stream.generate(Math::random) .limit(10).toList()); Note If you have an Iterable that is not a collection, you can turn it into a stream by calling StreamSupport.stream(iterable.spliterator(), false); If you have an Iterator and want a stream of its results, use StreamSupport.stream(Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED), false); Caution It is very important that you don’t modify the collection backing a stream while carrying out a stream operation. Remember that streams don’t collect their data—the data is always in a separate collection. If you modify that collection, the outcome of the stream operations becomes undefined. The JDK documentation refers to this requirement as noninterference. To be exact, since intermediate stream operations are lazy, it is possible to mutate the collection up to the point where the terminal operation executes. For example, the following, while certainly not recommended, will work: List<String> wordList = . . .; Stream<String> words = wordList.stream(); wordList.add("END"); long n = words.distinct().count(); But this code is wrong:
  • 36. Stream<String> words = wordList.stream(); words.forEach(s -> {if (s.length() < 12) wordList.remove(s);}); // ERROR--interference The example program in Listing 1.2 shows the various ways of creating a stream. Listing 1.2 streams/CreatingStreams.java 1 package streams; 2 3 import java.io.*; 4 import java.math.*; 5 import java.nio.file.*; 6 import java.util.*; 7 import java.util.regex.Pattern; 8 import java.util.stream.*; 9 10 /** 11 * @version 1.03 2021-09-06 12 * @author Cay Horstmann 13 */ 14 public class CreatingStreams 15 { 16 public static <T> void show(String title, Stream<T> stream) 17 { 18 final int SIZE = 10; 19 List<T> firstElements = stream 20 .limit(SIZE + 1) 21 .toList(); 22 System.out.print(title + ": "); 23 for (int i = 0; i < firstElements.size(); i++) 24 { 25 if (i > 0) System.out.print(", "); 26 if (i < SIZE)
  • 37. System.out.print(firstElements.get(i)); 27 else System.out.print("..."); 28 } 29 System.out.println(); 30 } 31 32 public static void main(String[] args) throws IOException 33 { 34 Path path = Path.of("../gutenberg/alice30.txt"); 35 var contents = Files.readString(path); 36 37 Stream<String> words = Stream.of(contents.split("PL+")); 38 show("words", words); 39 Stream<String> song = Stream.of("gently", "down", "the", "stream"); 40 show("song", song); 41 Stream<String> silence = Stream.empty(); 42 show("silence", silence); 43 44 Stream<String> echos = Stream.generate(() -> "Echo"); 45 show("echos", echos); 46 47 Stream<Double> randoms = Stream.generate(Math::random); 48 show("randoms", randoms); 49 50 Stream<BigInteger> integers = Stream.iterate(BigInteger.ONE, 51 n -> n.add(BigInteger.ONE)); 52 show("integers", integers); 53 54 Stream<String> greetings = "HellonGuten TagnBonjour".lines(); 55 show("greetings", greetings); 56 57 Stream<String> wordsAnotherWay = Pattern.compile("PL+").splitAsStream(contents); 58 show("wordsAnotherWay", wordsAnotherWay); 59
  • 38. 60 try (Stream<String> lines = Files.lines(path)) 61 { 62 show("lines", lines); 63 } 64 65 Iterable<Path> iterable = FileSystems.getDefault().getRootDirectories(); 66 Stream<Path> rootDirectories = StreamSupport.stream(iterable.spliterator(), false); 67 show("rootDirectories", rootDirectories); 68 69 Iterator<Path> iterator = Path.of("/usr/share/dict/words").iterator(); 70 Stream<Path> pathComponents = StreamSupport.stream(Spliterators.spliteratorUnknownSize( 71 iterator, Spliterator.ORDERED), false); 72 show("pathComponents", pathComponents); 73 } 74 } java.util.stream.Stream 8 • static <T> Stream<T> of(T... values) yields a stream whose elements are the given values. • static <T> Stream<T> empty() yields a stream with no elements. • static <T> Stream<T> generate(Supplier<T> s) yields an infinite stream whose elements are constructed by repeatedly invoking the function s. • static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) • static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> f)
  • 39. yield a stream whose elements are seed, f invoked on seed, f invoked on the preceding element, and so on. The first method yields an infinite stream. The stream of the second method comes to an end before the first element that doesn’t fulfill the hasNext predicate. • static <T> Stream<T> ofNullable(T t) 9 returns an empty stream if t is null or a stream containing t otherwise. java.util.Spliterators 8 • static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics) turns an iterator into a splittable iterator of unknown size with the given characteristics (a bit pattern containing constants such as Spliterator.ORDERED). java.util.Arrays 1.2 • static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) 8 yields a stream whose elements are the specified range of the array. java.lang.String • static Stream<String> lines() 11 yields a stream whose elements are the lines of this string.
  • 40. java.util.regex.Pattern 1.4 • Stream<String> splitAsStream(CharSequence input) 8 yields a stream whose elements are the parts of the input that are delimited by this pattern. java.nio.file.Files 7 • static Stream<String> lines(Path path) 8 • static Stream<String> lines(Path path, Charset cs) 8 yield a stream whose elements are the lines of the specified file, with the UTF-8 charset or the given charset. java.util.stream.StreamSupport 8 • static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) yields a stream containing the values produced by the given splittable iterator. java.lang.Iterable 5 • Spliterator<T> spliterator() 8 yields a splittable iterator for this Iterable. The default implementation does not split and does not report a size.
  • 41. java.util.Scanner 5 • public Stream<String> tokens() 9 yields a stream of strings returned by calling the next method of this scanner. java.util.function.Supplier<T> 8 • T get() supplies a value. 1.3 The filter, map, and flatMap Methods A stream transformation produces a stream whose elements are derived from those of another stream. You have already seen the filter transformation that yields a new stream with those elements that match a certain condition. Here, we transform a stream of strings into another stream containing only long words: List<String> words = . . .; Stream<String> longWords = words.stream().filter(w -> w.length() > 12); The argument of filter is a Predicate<T>—that is, a function from T to boolean.
  • 42. Often, you want to transform the values in a stream in some way. Use the map method and pass the function that carries out the transformation. For example, you can transform all words to lowercase like this: Stream<String> lowercaseWords = words.stream().map(String::toLowerCase); Here, we used map with a method reference. Often, you will use a lambda expression instead: Stream<String> firstLetters = words.stream().map(s -> s.substring(0, 1)); The resulting stream contains the first letter of each word. When you use map, a function is applied to each element, and the result is a new stream with the results. Occasionally, you are faced with a mapping function that generates an optional result, or more than one result. As an example, consider a method codePoints that yields all code points of a string. For example, codePoints("Hello ") would consist of "H", "e", "l", "l", "o", " ", " ". Note that the globe symbol (U+1F310) consists of two char values, so the codePoints method has to do some heavy lifting to make this happen. We will look at a couple of implementations momentarily. How should codePoints collect its multiple results? For the stream API, it is most natural if the method returns a Stream<String>. Now let’s map such a codePoints method on a stream of strings: Stream<Stream<String>> result = words.stream().map(w -> codePoints(w)); You will get a stream of streams, like [. . . ["y", "o", "u", "r"], ["b", "o", "a", "t"], . . .]. To flatten it out to a
  • 43. single stream [. . . "y", "o", "u", "r", "b", "o", "a", "t", . . .], use the flatMap method instead of map: Stream<String> flatResult = words.stream().flatMap(w -> codePoints(w)); // Calls codePoints on each word and flattens the results Now that you have seen how to use the codePoints method, how do you write it? The String class has a codePoints method that yields a stream of integer code points: "Hello ".codePoints() // A stream of integers 72, 101, 108, 108, 111, 32, 127760 Next, we need to transform each of the integers to a string containing the Unicode character with the given code point. Unfortunately, there is a technical difficulty. The codePoints method produces an IntStream, which is a little different from a Stream<Integer>, as you will see in Section 1.13, “Primitive Type Streams,” on p. 43. Instead of map, you use the mapToObj method to transform the elements. Perhaps surprisingly, there is no convenient method for turning an integer codepoint into a string. Here is the best I could come up with: public static Stream<String> codePoints(String s) { return s.codePoints().mapToObj(cp -> new String(new int [] { cp }, 0, 1)); } When using flatMap, you provide a method that produces a new stream for every stream element. As you have seen, that can be tedious. It can also be a little inefficient. The mapMulti method offers an alternative. Instead of producing a stream of results, you generate the results and pass them to a collector—an object of a class implementing the functional interface Consumer. For each result, invoke the collector’s accept method.
  • 44. Let’s do this with an example. The following loop produces the code points of a string s: int i = 0; while (i < s.length()) { int cp = sentence.codePointAt(i); // Do something with cp if (Character.isSupplementaryCodePoint(cp)) i += 2; else i++; } When calling mapMulti, you provide a function that is invoked with the stream element and the collector. In your function, pass your results to the collector. Stream<String> result = words.stream().mapMulti((s, collector) -> { int i = 0; while (i < s.length()) { int cp = sentence.codePointAt(i); collector.accept(cp); if (Character.isSupplementaryCodePoint(cp)) i += 2; else i++; } }); java.util.stream.Stream 8 • Stream<T> filter(Predicate<? super T> predicate) yields a stream containing the elements of this stream that fulfill the predicate.
  • 45. • <R> Stream<R> map(Function<? super T,? extends R> mapper) yields a stream containing the results of applying mapper to the elements of this stream. • <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) yields a stream obtained by concatenating the results of applying mapper to the elements of this stream. (Note that each mapper result is a stream.) • <R> Stream<R> mapMulti(BiConsumer<? super T,? super Consumer<R>> mapper) 16 For each stream element, the mapper is invoked , and all elements passed to the Consumer during invocation are added to the result stream. 1.4 Extracting Substreams and Combining Streams The call stream.limit(n) returns a new stream that ends after n elements (or when the original stream ends if it is shorter). This method is particularly useful for cutting infinite streams down to size. For example, Stream<Double> randoms = Stream.generate(Math::random).limit(100); yields a stream with 100 random numbers. The call stream.skip(n) does the exact opposite. It discards the first n elements. This is handy in our book reading example where, due to the way the split method works, the first element is an unwanted empty string. We can make it go away by calling skip:
  • 46. Stream<String> words = Stream.of(contents.split("PL+")).skip(1); The stream.takeWhile(predicate) call takes all elements from the stream while the predicate is true, and then stops. For example, suppose we use the codePoints method of the preceding section to split a string into characters, and we want to collect all initial digits. The takeWhile method can do this: Stream<String> initialDigits = codePoints(str).takeWhile( s -> "0123456789".contains(s)); The dropWhile method does the opposite, dropping elements while a condition is true and yielding a stream of all elements starting with the first one for which the condition was false. For example, Stream<String> withoutInitialWhiteSpace = codePoints(str).dropWhile( s -> s.strip().length() == 0); You can concatenate two streams with the static concat method of the Stream class: Stream<String> combined = Stream.concat( codePoints("Hello"), codePoints("World")); // Yields the stream ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"] Of course, the first stream should not be infinite—otherwise the second one wouldn’t ever get a chance. java.util.stream.Stream 8
  • 47. • Stream<T> limit(long maxSize) yields a stream with up to maxSize of the initial elements from this stream. • Stream<T> skip(long n) yields a stream whose elements are all but the initial n elements of this stream. • Stream<T> takeWhile(Predicate<? super T> predicate) 9 yields a stream whose elements are the initial elements of this stream that fulfill the predicate. • Stream<T> dropWhile(Predicate<? super T> predicate) 9 yields a stream whose elements are the elements of this stream except for the initial ones that do not fulfill the predicate. • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) yields a stream whose elements are the elements of a followed by the elements of b. 1.5 Other Stream Transformations The distinct method returns a stream that yields elements from the original stream, in the same order, except that duplicates are suppressed. The duplicates need not be adjacent. Stream<String> uniqueWords = Stream.of("merrily", "merrily", "merrily", "gently").distinct(); // Only one "merrily" is retained
  • 48. For sorting a stream, there are several variations of the sorted method. One works for streams of Comparable elements, and another accepts a Comparator. Here, we sort strings so that the longest ones come first: Stream<String> longestFirst = words.stream().sorted(Comparator.comparing(String::length).revers ed()); As with all stream transformations, the sorted method yields a new stream whose elements are the elements of the original stream in sorted order. Of course, you can sort a collection without using streams. The sorted method is useful when the sorting process is part of a stream pipeline. Finally, the peek method yields another stream with the same elements as the original, but a function is invoked every time an element is retrieved. That is handy for debugging: Object[] powers = Stream.iterate(1.0, p -> p * 2) .peek(e -> System.out.println("Fetching " + e)) .limit(20).toArray(); When an element is actually accessed, a message is printed. This way you can verify that the infinite stream returned by iterate is processed lazily. Tip When you use a debugger to debug a stream computation, you can set a breakpoint in a method that is called from one of the transformations. With most IDEs, you can also set breakpoints in lambda expressions. If you just want to know what happens at a particular point in the stream pipeline, add
  • 49. .peek(x -> { return; }) and set a breakpoint on the second line. java.util.stream.Stream 8 • Stream<T> distinct() yields a stream of the distinct elements of this stream. • Stream<T> sorted() • Stream<T> sorted(Comparator<? super T> comparator) yield a stream whose elements are the elements of this stream in sorted order. The first method requires that the elements are instances of a class implementing Comparable. • Stream<T> peek(Consumer<? super T> action) yields a stream with the same elements as this stream, passing each element to action as it is consumed. 1.6 Simple Reductions Now that you have seen how to create and transform streams, we will finally get to the most important point—getting answers from the stream data. The methods covered in this section are called reductions. Reductions are terminal operations. They reduce the stream to a nonstream value that can be used in your program. You have already seen a simple reduction: the count method that returns the number of elements of a stream.
  • 50. Other simple reductions are max and min that return the largest or smallest value. There is a twist—these methods return an Optional<T> value that either wraps the answer or indicates that there is none (because the stream happened to be empty). In the olden days, it was common to return null in such a situation. But that can lead to null pointer exceptions when it happens in an incompletely tested program. The Optional type is a better way of indicating a missing return value. We discuss the Optional type in detail in the next section. Here is how you can get the maximum of a stream: Optional<String> largest = words.max(String::compareToIgnoreCase); System.out.println("largest: " + largest.orElse("")); The findFirst returns the first value in a nonempty collection. It is often useful when combined with filter. For example, here we find the first word that starts with the letter Q, if it exists: Optional<String> startsWithQ = words.filter(s -> s.startsWith("Q")).findFirst(); If you are OK with any match, not just the first one, use the findAny method. This is effective when you parallelize the stream, since the stream can report any match that it finds instead of being constrained to the first one. Optional<String> startsWithQ = words.parallel().filter(s -> s.startsWith("Q")).findAny(); If you just want to know if there is a match, use anyMatch. That method takes a predicate argument, so you won’t need to use filter. boolean aWordStartsWithQ = words.parallel().anyMatch(s -> s.startsWith("Q"));
  • 51. There are methods allMatch and noneMatch that return true if all or no elements match a predicate. These methods also benefit from being run in parallel. java.util.stream.Stream 8 • Optional<T> max(Comparator<? super T> comparator) • Optional<T> min(Comparator<? super T> comparator) yield a maximum or minimum element of this stream, using the ordering defined by the given comparator, or an empty Optional if this stream is empty. These are terminal operations. • Optional<T> findFirst() • Optional<T> findAny() yield the first, or any, element of this stream, or an empty Optional if this stream is empty. These are terminal operations. • boolean anyMatch(Predicate<? super T> predicate) • boolean allMatch(Predicate<? super T> predicate) • boolean noneMatch(Predicate<? super T> predicate) return true if any, all, or none of the elements of this stream match the given predicate. These are terminal operations. 1.7 The Optional Type An Optional<T> object is a wrapper for either an object of type T or no object. In the former case, we say that the value is present. The
  • 52. Optional<T> type is intended as a safer alternative for a reference of type T that either refers to an object or is null. But it is only safer if you use it right. The next three sections shows you how. 1.7.1 Getting an Optional Value The key to using Optional effectively is to use a method that either produces an alternative if the value is not present, or consumes the value only if it is present. In this section, we look at the first strategy. Often, there is a default that you want to use when there was no match, perhaps the empty string: String result = optionalString.orElse(""); // The wrapped string, or "" if none You can also invoke code to compute the default: String result = optionalString.orElseGet(() -> System.getProperty("myapp.default")); // The function is only called when needed Or you can throw an exception if there is no value: String result = optionalString.orElseThrow(IllegalStateException::new); // Supply a method that yields an exception object java.util.Optional 8 • T orElse(T other) yields the value of this Optional, or other if this Optional is empty. • T orElseGet(Supplier<? extends T> other)
  • 53. yields the value of this Optional, or the result of invoking other if this Optional is empty. • <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) yields the value of this Optional, or throws the result of invoking exceptionSupplier if this Optional is empty. 1.7.2 Consuming an Optional Value In the preceding section, you saw how to produce an alternative if no value is present. The other strategy for working with optional values is to consume the value only if it is present. The ifPresent method accepts a function. If the optional value exists, it is passed to that function. Otherwise, nothing happens. optionalValue.ifPresent(v -> Process v); For example, if you want to add the value to a set if it is present, call optionalValue.ifPresent(v -> results.add(v)); or simply optionalValue.ifPresent(results::add); If you want to take one action if the Optional has a value and another action if it doesn’t, use ifPresentOrElse: optionalValue.ifPresentOrElse( v -> System.out.println("Found " + v), () -> logger.warning("No match"));
  • 54. java.util.Optional 8 • void ifPresent(Consumer<? super T> action) If this Optional is nonempty, passes its value to action. • void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) 9 If this Optional is nonempty, passes its value to action, else invokes emptyAction. 1.7.3 Pipelining Optional Values In the preceding sections, you saw how to get a value out of an Optional object. Another useful strategy is to keep the Optional intact. You can transform the value inside an Optional by using the map method: Optional<String> transformed = optionalString.map(String::toUpperCase); If optionalString is empty, then transformed is also empty. Here is another example. We add a result to a list if it is present: optionalValue.map(results::add); If optionalValue is empty, nothing happens. Note This map method is the analog of the map method of the Stream interface that you have seen in Section 1.3, “The filter, map, and flatMap Methods,” on p. 11. Simply imagine an optional value as a
  • 55. Random documents with unrelated content Scribd suggests to you:
  • 56. "Do you know that lady!" I heard them ask. "Yes, and the nigger too. It's Miss Salome Poillon, and she lives at S —— plantation, across the river," was the answer. "Then she is a resident here, and there is no danger of their being spies?" put in the cautious one. "Lord, no! Why, she's the biggest Rebel 'round. So's all the family, an' she's got a Rebel lover," replied my champion emphatically, adding the last fact as if it were a clincher. That settled it, and the two officers then came over to the carriage and told me I was at liberty to go on, and regretted that they had been obliged to stop me at all. I thanked them, and asked if I would have much difficulty in getting through. "I am afraid so," replied the one who had first met me. "This is your most direct route, is it not?" asked the older officer, on whom the rest of the conversation devolved. "It is much the nearest way," I replied. "It leads directly on, near where a considerable body of our troops are, yet I think it will be safer for you to keep it than to try side roads, where you would be constantly stopped. I will give you a note to the general in command, and a pass, which will aid you until you reach him. He will likely give you an escort for some distance," he added, writing as he spoke. When he handed me the papers, I asked him about the positions of the Yankees, and in answering he told me also something new about how Luce's army was located, which was one of the clues that I wanted to learn. I had no idea of using the papers unless I should fail in all efforts to find Captain DeLacy. I told Ned not to refer to them in any way or to our encounter, while he should be separated from me, and
  • 57. impressed on him that he was not to get out of the buggy if he could help it, or leave the horses one moment unless dragged away by force. I regretted that we had run into the camp, for it took valuable time, and it did not make me feel any better about it to know that it had happened through my own carelessness. If I had been watching out, as I ought to have been, I would have noticed the fires in time to have avoided them by making a detour, and I believed that I could have gotten later the valuable bit of information the talkative officer had given me.
  • 58. CHAPTER XI. The encounter had one good result, however. It got us over our stage fright, as it were, and rather raised us up to the grand climax. We had driven nearly three miles farther before we ran into the Rebel camp again. When we finally found ourselves making our way under guard to General Dare's headquarters, we were far more composed than we could possibly have been had we not already had some experience. When stopped, I had insisted on being allowed to proceed, but as I expected and desired, the simple privilege of following my own way was denied me. My statements regarding my identity were received with incredulity. I insisted on the truth of my story, and I demanded that I be taken to headquarters at once. After some parley, my request was acceded to and a couple of soldiers took their places at the horses' heads and slowly led them forward, while a guard walked at the side of the buggy until we reached a cluster of tents pitched somewhat apart, in front of which stood four or five officers conversing. The officer who had brought us in advanced to the group, and I could hear him reporting the circumstances of our arrest. A handsome subaltern came forward to assist me from the buggy, and I was soon answering the curtly-put inquiries of the middle aged officer to whom I had been conducted. I repeated my story. He questioned and cross-questioned me severely, but I was too entirely familiar with my ground to be caught tripping. I felt a good deal as if I were an actor in a play, and while I must say that I did not particularly admire the setting, I began to have an intense interest in rendering my part well and having all go off smoothly.
  • 59. Ned was seated in the buggy within hearing distance and I saw he had assumed, or was really feeling, about the right amount of anxiety, and that no one seemed to be paying any attention whatever to him. I did not recognize the officer interrogating me, but I heard him addressed by one of the other officers as Colonel Sofield. When after telling him my story, he utterly refused to credit it. I asked to see the General in command. Col. Sofield replied that General Senhouse had gone over to confer with General Leonard and might not be back until morning, not for several hours certainly, and followed the explanation with an intimation that both myself and my servant would be well off under guard until his return. I was somewhat nonplussed when the officer said General Senhouse. I had looked on General Dare only as a guide to Captain DeLacy, and had no interest whatever beyond that in him. At the same time I was a trifle surprised that I had not been taken before him, and that reference had not been made to him instead of to General Senhouse. I began to wonder if it were possible that I had not reached Dare's headquarters, but I did not dare ask directly or betray more knowledge of army details than a girl would be likely to know. After pondering a moment, I said: "I ought perhaps to have stopped at A——, as I was advised to do, but I was so very anxious to get on, that I could not make up my mind to delay there. Will you tell me what regiment this is? I have friends and relatives with General Luce and there may be some one here who can identify me." An orderly was presenting a paper to Col. Sofield as I finished speaking, and another officer, who had come up but a short time previous and was standing near, in company with the others, answered: "This is General Dare's division, but General Senhouse is in command at present. Over on the left there is the —— Regiment,
  • 60. —— Brigade; others are further on. If you will give the names of your friends, and they are here, they can be sent for." "Captain DeLacy is with General Dare. If I could see him, he would assure you that I am just who I represent myself. He is a very intimate friend of the family," I said, turning again to my first interlocuter. "Impossible," he replied, "Captain DeLacy has just started to inspect a position several miles from here. There is no telling when he will be back." "Beg pardon, Colonel, but Captain DeLacy has not got off yet. He passed us on the way over here, and I saw him go in Colonel Lounsbery's tent a few minutes ago," spoke up another officer. "There he comes now," he added, as a tall figure came out of a tent near by. Affairs progressed rapidly in the next few minutes. In less time than I could write it, Captain DeLacy had been called over to identify me; had done it, even to the satisfaction of the obdurate Colonel, and beard the story of my detention, and my anxious request that I might go on at once. Captain DeLacy asked and received permission to take me into a neighboring tent, where I could wait, freed from the gaze of those who had gathered around to see what was going on, until he could procure the passes necessary to insure my safe conduct through their lines. Colonel Sofield, whose good manners had increased in proportion to the strengthening of his convictions that I was not a spy, told him to take me into General Dare's tent, as it was the nearest one unoccupied, then to return to him for passes. A moment later I was alone with the only man of them all who could penetrate my disguise. His first words assured me that he had not heard from Salome lately enough to imperil my statements. And his hurried whispers of love and devotion, together with his grave concern at my having undertaken a journey through that section at
  • 61. so dangerous a time, proved that he accepted me in perfect good faith. Even at that desperate moment, at the touch of the Captain's lips I was filled with an unholy glee. Fortunately, he had little time to play the lover. Love and war are an ill-matched couple, and except that both set at naught all interfering laws, they have nothing in common. The latter never relaxes the grasp of a master and exacts that all who serve him shall fulfill their duty to the utmost, without delay or flinching, although by so doing all pleasures, affections, ties of kindred and life itself are yielded up. My expressed anxiety for his safety, and pretended impression that he was on some dangerous raid, led Captain DeLacy to assure me that he was with Luce, and to tell me what forces Luce had with him, but no more about his future movements than I had already gathered, which amounted to but little beyond a clue to the meaning of General Middleworth's movement, which I had witnessed that afternoon. I questioned as closely as I dared, but elicited nothing further. My shrewdest efforts were a failure. I saw that he either had not been informed of the object of the campaign, or felt bound not to reveal it even to one whom he held as dear as he did Salome.
  • 62. CHAPTER XII. While conversing with Captain DeLacy, I had become as familiar with the interior of the tent as I could by the light of one inferior candle and the use of my eyes. There seemed nothing there to invite investigation. Even after Captain DeLacy had reluctantly left me, a closer inspection revealed nothing more promising. I sat on a camp stool, in a corner; near was a pile of blankets; a rough camp chair stood between me and the bed; a bayonet stuck in the ground did duty for a candlestick, and on an empty wooden box near me lay a paper- covered book. I had just had time to run a hasty glance through the book, when the fly was raised and an officer entered. As was only natural, he started when he saw me, then lifted his hat with a half-spoken apology, tossed a newspaper carelessly on the bed, threw his overcoat over the chair and went out again. I recognized him instantly as General Dare. His actions and looks struck me as those of a man who felt at odds with the world and who was nursing a grievance, but I was too deeply concerned about my own affairs to be more than casually impressed with what I learned afterwards was the case. It is a strange fact that in times of most intense suffering, deadly peril and deepest thought, the eye will be attracted by the most trivial objects. While I anxiously pondered my next move, my eye mechanically followed in and out the fantastically curved line made by the shadows cast by the pile of blankets, then by the edge of the coat cape as it trailed along the floor. I had followed it almost to the end when my gaze was arrested by a spot of color differing from the rest. With a start, I realized that I was looking at a flat, long book. I
  • 63. could not tell then and I cannot tell now whether it fell from the overcoat or was lying there when I entered, but I do not see how it could have been there at first and escaped my observation. I determined at once to see the contents of that book. There was not one instant to be lost. I well knew that even then some one might be standing at the entrance and that the Captain would return at any moment. But examine that book I must, even at the risk of surprise, detection and death. It was the most critical moment I had yet encountered. I had to think and act together. Throwing myself at full length on the grassy floor, with my head screened from the first glance of any one entering, intending to feign a swoon if any one did come, I extended my arm above my head, in the shelter of the chair, and had the book in my impatient fingers. Opening it hastily, I scanned it in the dim light which came over my shoulder from the flickering candle. I was confronted by a series of blank pages. General Dare's name was on the fly leaf. Only the first three pages were written on, and they contained nothing except detached items of interest to him only. Evidently, the book had been newly purchased, for the dates ran but a few days back. Bitterly disappointed, I ran over the pages again, and a folded paper slipped into view. Even to this day I can distinctly feel the wild bound of exultation my heart gave when I knew that I held in my hands a copy of Special Order No. 000, issued by the Rebel Commander in Chief only four days before, and regulating the movements of all the divisions of his army for several days to come. At the sight of that paper every drop of blood in my body seemed to rush to my heart, only to leave it again with a wild speed that turned me faint and dizzy. The letters danced before my eyes, but even in that one hasty glance I took in enough to know that I need seek no further information. I had succeeded even beyond my hopes and expectations. If I could get safely back with that paper, and
  • 64. whatever else I had learned, I felt check to the Rebels must be insured. Hastily concealing the paper, I pushed the book under the bed, and had barely regained my place when Captain DeLacy re-entered with the passes. There was no time for further private conversation between us, which I regarded as a piece of good luck. Captain DeLacy told me, while he hastily assorted the papers in his hand, that he was obliged to proceed without delay on the important duty for which he was preparing when Colonel Sofield had called him to me; that as the first part of our way lay the same as his, he could act as my escort until his road turned off from the one I was to follow. From where he had to leave me, to H—— was only ten miles, and he exacted a promise that I would remain there with friends until morning. I could not but be touched at his anxiety about me, impatient as I was at the delay which it caused. We started almost immediately. Captain DeLacy rode at the side of the buggy and the squad of men with him a short distance in advance. The road was clear, and we made excellent time. At last the moment of separation came. His real farewell had already been said, so before following his men down the dark path, into which they had turned, the Captain paused only for some cautions to Ned and a quickly spoken "good bye" to me, which held as much as was ever put in that simple word. I realized fully what the parting was to him. He had accepted me as Salome, without doubt or question, and to leave me with no other protector than Ned tried him sorely. I leaned out of the buggy and looked back after him, with a feeling of pain that surprised me. As he disappeared, a presentment that I should never see him again crept over me, followed by an idle speculation whether it was he or I who was first to meet our fate, a
  • 65. feeling which I remembered well a few months later, when I received the news that Captain DeLacy had been shot in battle.
  • 66. CHAPTER XIII. Shaking off the dim sense of foreboding, I gave my thoughts entirely to the task before me. I had decided to make my way down the side of the river I was then on. From what I had learned of the position of the enemy, I knew the risk would be no greater than if I crossed to the opposite shore, and I hoped to save many weary miles of travel. Being well aware of the extreme caution shown on our side, I thought the chances were that our army would be yet in the neighborhood of the place where I left them, and I aimed for that point. I told Ned that I had secured a paper of the utmost importance, and that if I were shot and he escaped, he was to take the paper from its place of concealment and carry it on. We turned to the left, down the first road we came to, after parting with Captain DeLacy and his men. Just before we reached it, we were stopped by a small party of Confederates on horseback. I offered my passes. Striking a match, an officer read them, and after a few questions, allowed us to go on. That was the only time the passes were of use to us, for as soon as I parted with my disguise they were, of course, worthless. In order to make the best time possible, and avail ourselves of short cuts and bridle paths, it was necessary to leave the buggy and return to horseback. That we did at the earliest practical moment. As soon as we came to a rough bit of road, after our first turn, Ned drove the buggy to one side, and, knocking off a wheel, left it to its fate. When I was again in my own clothes, we made the harness and my disguise into several bundles, which Ned weighted and dropped into the first creek we came to.
  • 67. That done, we hurried on. The night had turned cloudy and dark while we had been in the Confederate camp. It did not rain, but before long we struck a place where it had very recently, and our horses for a short distance were obliged to plough through slippery clay. Frequently we would see the fires of some outpost, and often a picket shot, sometimes startlingly near, would ring out on the murky night. Well as I knew the country, I finally made a false turn in the confusing darkness, and approached the river when I thought we were still several miles away from it and following its course. Leaving Ned in safe hiding, I crept forward to reconnoiter. I made for a rock overhanging the water, at the head of a bend in the river, from the edge of which I hoped to be able to tell if the fires opposite were repeated down the side I was on. As I gained a sheltered place near the top and in the rear of the rock, I heard a boat grate on the pebbles beneath, and two men ascended to the very spot I had started for. I lay low behind the scanty bushes, while they sat down near me. From what they said, I gathered that they had crossed from the Rebel camp over the river to investigate the bank up stream for some purpose, but not liking the looks of something that had attracted their notice, they had stopped there to decide what they should do. I was too near to move away without them hearing me. I was caught in a trap. Chaffing at a delay, when every moment was precious, and fearing that Ned, alarmed at my protracted absence, might come to look for me, I was obliged to crouch, motionless in my hiding place, while the two men so near me idly discussed topics relating to everything but the duty they were on. While I waited, the clouds began to break away, and once or twice the moonlight shone out full and strong, leaving me with little to shield me, had they chanced to turn around.
  • 68. Finally, after what seemed hours to me, one decided to go over for re-enforcements and descended to the boat. Cautiously rising, as the other advanced to the extreme edge of the rock, I saw that his back was toward me and that he was intently watching the progress of the boat, then in mid-stream. It was possible then for me to have slipped away unnoticed, but I was exasperated beyond endurance. An uncontrollable impulse seized me. Even if I had been sure that the whole Confederate army would have started to his rescue, I could not have helped pushing that man into the water. Moving noiselessly behind him, with the end of my revolver I gave him a sharp punch in the middle of the back. Taken completely off his guard, without a word, but with a wild whirl of arms and legs, he went straight down into the deep water beneath. I have wondered hundreds of times since, what that man thought was the matter with him. If he has lived to read this, he knows now.
  • 69. CHAPTER XIV. I returned to where Ned was, and we began retracing our steps. Although we made frequent attempts to get news, it was not until nearly morning that I learned that our troops had advanced to a point, nearer the place where I had made my way into the enemy's camp, and, consequently, nearer where I was then, but to my left. We immediately changed our route. From the moment the order had fallen into my hands, my one desire and aim was to get it where the information it contained, together with what other I had gathered, could be put to instant use. Every nerve throbbed with impatience. Every delay was intolerable. Yet that entire ride back was a series of vexatious and dangerous delays. I was beset on every side by dangers, which closed in on me at every point where I tried to evade them. Every mile counted for four in my eagerness to get on. I was obliged, time after time, to retrace my steps and make long detours to avoid running into bodies of skirmishers, to escape the vigilance of pickets, and to baffle the pursuers on our tracks. Twice that night we stood with our coats drawn tightly over our horses' heads to keep them from making a sound to betray our presence to the enemy, passing so closely below that by stooping, we could have lifted the hats off of their heads with a ramrod. Shortly after daybreak, as the first rays of of the sun showed over a neighboring hill, I lay in a hollow log, while a man from the column of passing soldiers sat on it to beat the dirt and stones from his remnants of shoes. The dust from the inside of the log, loosened by his pounding, choked me, until in my efforts to keep from coughing, I bit through the sleeve of my coat, and left the print of my teeth on
  • 70. my arm. About six hundred soldiers marched past me, as I watched them from a crevice in the log. Across the road and half way up the hill beyond I could see where Ned crouched, keeping the horses back in the shelter of a low thicket. Knowing exactly where to look for him, he stood out with terrible distinctness to my abnormally keen sight, and I trembled whenever I saw a soldier turn his head in that direction. Even now, as I think it over, with all my increased experience and knowledge of hair-breadth escapes, it seems simply incredible that we ever got through. But get through we did. By eight o'clock, exhausted to faintness from hard riding, lack of food and loss of sleep, and with horses reeling from fatigue, we turned out onto a road which in a few minutes took us beyond danger. Loyal hands placed fresh horses at our disposal, and with little loss of time, we were covering the last ten miles of our ride. Soon the bit of paper, that "Lost Dispatch," which through all that long and fearful night had been the elixir that nerved me to my work, was in the hands of the proper officer, and I had communicated to him the additional information I had gathered. Both information and dispatch, without delay, were carried to the Commander in Chief. I only did my duty. My responsibility ended there. But looking back now, it seems, as it did then, that better results should have been obtained through a quick action on the intelligence gathered. THE END.
  • 71. *** END OF THE PROJECT GUTENBERG EBOOK THE LOST DISPATCH *** Updated editions will replace the previous one—the old editions will be renamed. Creating the works from print editions not protected by U.S. copyright law means that no one owns a United States copyright in these works, so the Foundation (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth in the General Terms of Use part of this license, apply to copying and distributing Project Gutenberg™ electronic works to protect the PROJECT GUTENBERG™ concept and trademark. Project Gutenberg is a registered trademark, and may not be used if you charge for an eBook, except by following the terms of the trademark license, including paying royalties for use of the Project Gutenberg trademark. If you do not charge anything for copies of this eBook, complying with the trademark license is very easy. You may use this eBook for nearly any purpose such as creation of derivative works, reports, performances and research. Project Gutenberg eBooks may be modified and printed and given away—you may do practically ANYTHING in the United States with eBooks not protected by U.S. copyright law. Redistribution is subject to the trademark license, especially commercial redistribution. START: FULL LICENSE
  • 72. THE FULL PROJECT GUTENBERG LICENSE
  • 73. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg™ mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase “Project Gutenberg”), you agree to comply with all the terms of the Full Project Gutenberg™ License available with this file or online at www.gutenberg.org/license. Section 1. General Terms of Use and Redistributing Project Gutenberg™ electronic works 1.A. By reading or using any part of this Project Gutenberg™ electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg™ electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg™ electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. “Project Gutenberg” is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg™ electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg™ electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg™ electronic works. See paragraph 1.E below.
  • 74. 1.C. The Project Gutenberg Literary Archive Foundation (“the Foundation” or PGLAF), owns a compilation copyright in the collection of Project Gutenberg™ electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is unprotected by copyright law in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, displaying or creating derivative works based on the work as long as all references to Project Gutenberg are removed. Of course, we hope that you will support the Project Gutenberg™ mission of promoting free access to electronic works by freely sharing Project Gutenberg™ works in compliance with the terms of this agreement for keeping the Project Gutenberg™ name associated with the work. You can easily comply with the terms of this agreement by keeping this work in the same format with its attached full Project Gutenberg™ License when you share it without charge with others. 1.D. The copyright laws of the place where you are located also govern what you can do with this work. Copyright laws in most countries are in a constant state of change. If you are outside the United States, check the laws of your country in addition to the terms of this agreement before downloading, copying, displaying, performing, distributing or creating derivative works based on this work or any other Project Gutenberg™ work. The Foundation makes no representations concerning the copyright status of any work in any country other than the United States. 1.E. Unless you have removed all references to Project Gutenberg: 1.E.1. The following sentence, with active links to, or other immediate access to, the full Project Gutenberg™ License must appear prominently whenever any copy of a Project Gutenberg™ work (any work on which the phrase “Project Gutenberg” appears, or with which the phrase “Project Gutenberg” is associated) is accessed, displayed, performed, viewed, copied or distributed:
  • 75. This eBook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. 1.E.2. If an individual Project Gutenberg™ electronic work is derived from texts not protected by U.S. copyright law (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase “Project Gutenberg” associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg™ electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg™ License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg™ License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg™. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1
  • 76. with active links or immediate access to the full terms of the Project Gutenberg™ License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg™ work in a format other than “Plain Vanilla ASCII” or other format used in the official version posted on the official Project Gutenberg™ website (www.gutenberg.org), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original “Plain Vanilla ASCII” or other form. Any alternate format must include the full Project Gutenberg™ License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg™ works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg™ electronic works provided that: • You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg™ works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg™ trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, “Information
  • 77. about donations to the Project Gutenberg Literary Archive Foundation.” • You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg™ License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg™ works. • You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. • You comply with all other terms of this agreement for free distribution of Project Gutenberg™ works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™ electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from the Project Gutenberg Literary Archive Foundation, the manager of the Project Gutenberg™ trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread works not protected by U.S. copyright law in creating the Project Gutenberg™ collection. Despite these efforts, Project Gutenberg™ electronic works, and the medium on which they may be stored, may contain “Defects,” such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or
  • 78. damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right of Replacement or Refund” described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg™ trademark, and any other party distributing a Project Gutenberg™ electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
  • 79. INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg™ electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg™ electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg™ work, (b) alteration, modification, or additions or deletions to any Project Gutenberg™ work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg™ Project Gutenberg™ is synonymous with the free distribution of electronic works in formats readable by the widest variety of computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need are critical to reaching Project Gutenberg™’s goals and ensuring that the Project Gutenberg™ collection will
  • 80. remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg™ and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation information page at www.gutenberg.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non-profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation’s EIN or federal tax identification number is 64-6221541. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state’s laws. The Foundation’s business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up to date contact information can be found at the Foundation’s website and official page at www.gutenberg.org/contact Section 4. Information about Donations to the Project Gutenberg Literary Archive Foundation Project Gutenberg™ depends upon and cannot survive without widespread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine-readable form accessible by the widest array of equipment including outdated equipment. Many
  • 81. small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit www.gutenberg.org/donate. While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg web pages for current donation methods and addresses. Donations are accepted in a number of other ways including checks, online payments and credit card donations. To donate, please visit: www.gutenberg.org/donate. Section 5. General Information About Project Gutenberg™ electronic works Professor Michael S. Hart was the originator of the Project Gutenberg™ concept of a library of electronic works that could be freely shared with anyone. For forty years, he produced and distributed Project Gutenberg™ eBooks with only a loose network of volunteer support.
  • 82. Project Gutenberg™ eBooks are often created from several printed editions, all of which are confirmed as not protected by copyright in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our website which has the main PG search facility: www.gutenberg.org. This website includes information about Project Gutenberg™, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks.
  • 83. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com