Java Reference
In-Depth Information
in which case, the compiler determines the parameter and return types by the lambda's
context—we'll say more about this later.
When the body contains only one expression, the
return
keyword and curly braces
may be omitted, as in:
(x, y) -> x + y
in this case, the expression's value is
implicitly
returned. When the parameter list contains
only one parameter, the parentheses may be omitted, as in:
value -> System.out.printf(
"%d "
, value)
To define a lambda with an empty parameter list, specify the parameter list as empty
parentheses to the left of the arrow token (
->
), as in:
() -> System.out.println(
"Welcome to lambdas!"
)
In addition, to the preceding lambda syntax, there are specialized shorthand forms of
lambdas that are known as
method references
, which we introduce in Section 17.5.1.
Java SE 8 introduces the concept of
streams
, which are similar to the iterators you learned
in Chapter 16. Streams are objects of classes that implement interface
Stream
(from the
package
java.util.stream
) or one of the specialized stream interfacess for processing col-
lections of
int
,
long
or
double
values (which we introduce in Section 17.3). Together
with lambdas, streams enable you to perform tasks on collections of elements—often from
an array or collection object.
Stream Pipelines
Streams move elements through a sequence of processing steps—known as a
stream pipe-
line
—that begins with a
data source
(such as an array or collection), performs various
in-
termediate operations
on the data source's elements and ends with a
terminal operation
. A
stream pipeline is formed by
chaining
method calls. Unlike collections, streams do
not
have
their own storage—once a stream is processed, it cannot be reused, because it does not
maintain a copy of the original data source.
Intermediate and Terminal Operations
An
intermediate operation
specifies tasks to perform on the stream's elements and always
results in a new stream. Intermediate operations are
lazy
—they aren't performed until a
terminal operation is invoked. This allows library developers to optimize stream-process-
ing performance. For example, if you have a collection of 1,000,000
Person
objects and
you're looking for the
first
one with the last name
"Jones"
, stream processing can termi-
nate as soon as the first such
Person
object is found.
A
terminal operation
initiates processing of a stream pipeline's intermediate opera-
tions and produces a result. Terminal operations are
eager
—they perform the requested
operation when they are called. We say more about lazy and eager operations as we
encounter them throughout the chapter and you'll see how lazy operations can improve
performance. Figure 17.3 shows some common intermediate operations. Figure 17.4
shows some common terminal operations.