Java8 Lambda Expressions Streams Sample
Java8 Lambda Expressions Streams Sample
Streams
Mastering Java 8 Lambdas and Streams
Fu Cheng
This book is for sale at http://leanpub.com/java8-lambda-expressions-streams
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2. Lambda expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1 Start a thread - A simple example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 Functional interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Target typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Lambda expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.5 Lexical scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.6 Effectively final local variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.7 Method references . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.7.1 Types of method references . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.8 Default interface methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.8.1 Static interface methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3. Optional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1 What’s Optional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Usage of Optional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.1 Simple usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.2 Chained usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.3 Functional usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 How-tos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.3.1 How to interact with legacy library code before Optional? . . . . . . . 15
3.3.2 How to get value from chained Optional reference path? . . . . . . . . 15
3.3.3 How to get first value of a list of Optionals? . . . . . . . . . . . . . . . . 16
3.3.4 How to chain method invocations with return value of Optional
objects in sequence? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.5 How to convert an Optional object to a stream? . . . . . . . . . . . . . . 19
3.3.6 How to use Optional to check for null and assign default values? . . . 20
3.4 Updates after Java 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4. Thank you . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1. Introduction
This book is not the first book about Java 8 lambda expressions and streams, and it’s definitely not
the last one. Java 8 is a Java platform upgrade which the community has been looking forward to
for a long time. Lambda expressions and streams quickly gain popularity in Java developers. There
are already a lot of books and online tutorials about lambda expressions and streams. This book is
trying to explain lambda expressions and streams from a different perspective.
• For lambda expressions, this book explains in details based on JSR 335.
• For streams, this book covers fundamental concepts of Java core library.
• This book provides how-to examples for lambda expressions and streams.
• This book also covers the important utility class Optional.
Lambda expressions and streams are easy to understand and use. This book tries to provide some
insights about how to use them efficiently.
You can purchase and down PDF/EPUB/MOBI version of this book on Leanpub¹.
¹https://leanpub.com/java8-lambda-expressions-streams
2. Lambda expressions
When people are talking about Java 8, lambda expression is always the first feature to mention.
Lambda expression in Java 8 brings functional programming style into Java platform, which has
been demanded by Java developers in the community for a long time. Lambda expression is also
widely used as a marketing term to promote Java 8 upgrade.
Lambda expressions can increase developers’ productivity in many ways. There are a lot of books
and online tutorials about Java 8 lambda expressions. This chapter is trying to explain lambda
expressions from a different perspective based on the official JSR 335: Lambda Expressions for the
JavaTM Programming Language¹. This chapter also provides how-tos for real programming tasks.
The small Java program in Listing 2.1 has 9 lines of code, but only one line of code (line 5) does the
real work. All the rest are just boilerplate code. To increase productivity, boilerplate code should be
removed as much as possible.
In Listing 2.1, line 1, 2, 8 and 9 are required for Java program to run, so these lines cannot
be removed. Line 3 to 7 create a new java.lang.Thread object with an implementation of
java.lang.Runnable interface, then invoke Thread object’s start() method to start the thread.
Runnable interface is implemented using an anonymous inner class.
¹https://jcp.org/en/jsr/detail?id=335
Lambda expressions 3
To simplify the code, new Runnable() in line 3 and 7 can be removed because the interface type
Runnable can be deduced from allowed constructors of Thread class. Line 4 and 6 can also be
removed, because run() is the only method in Runnable interface.
After removing boilerplate code in line 3, 4, 6 and 7, we get the new code using lambda expressions
in Listing 2.2.
Listing 2.2 Lambda expressions style to start a thread
The new Java program in Listing 2.2 only has 5 lines of code and the core logic is implemented with
only one line of code. Lambda expression () -> System.out.println("Hello World!") does
the same thing as anonymous class in Listing 2.1, but using lambda expression is concise and elegant
and easier to understand with less code. Less code means increasing productivity.
Simply put, lambda expression is the syntax sugar to create anonymous inner classes. But there are
more to discuss about lambda expressions.
• java.lang.Runnable
• java.util.concurrent.Callable
• java.util.Comparator
• java.io.FileFilter
Java SE 8 adds a new package java.util.function which includes new functional interfaces.
Java developers don’t need to care too much about the concept of functional interfaces. If we are
trying to use lambda expressions with non-functional interfaces, compiler will throw errors, then
Lambda expressions 4
we’ll know about that. Modern IDEs can also do checks for us. For API and library authors, if an
interface is designed to be functional, it should be marked with @FunctionalInterface annotation.
Compiler will generate an error if the interface doesn’t meet the requirements of being a functional
interface.
In Listing 2.3, lambda expression in line 1 only has one formal parameter, so parentheses are omitted.
Expression’s body is a single expression, so braces are also omitted. Formal parameter list has
no type declaration, so the type of list is implicitly inferred by compiler. Lambda expression
in line 3 has two formal parameters, so parentheses around parameters list are required. Lambda
expression in line 5 has explicit type for formal parameters x and y. Lambda expression in line 7 has
no formal parameters. In this case, parentheses are required. Lambda expression starts from line 9
is a complicated example with three formal parameters and multiple lines of code in body. In this
case, braces are required to wrap the body.
Lambda expression’s body can return a value or nothing. If a value is returned, the type of return
value must be compatible with target type. If an exception is thrown by the body, the exception must
be allowed by target type’s throws declaration.
Lambda expressions don’t introduce a new level of scoping. They are lexically scoped, which means
names in lambda expression’s body are interpreted as they are in the expression’s enclosing context.
So lambda expression body is executed as it’s in the same context of code enclosing it, except that
the body can also access expression’s formal parameters. this used in the expression body has the
same meaning as in the enclosing code.
Listing 2.4 Lexical scoping of lambda expression
public void run() {
String name = "Alex";
new Thread(() -> System.out.println("Hello, " + name)).start();
}
In Listing 2.4, lambda expression uses variable name from enclosing context. Listing 2.5 shows the
usage of this in lambda expression body. this is used to access sayHello method in the enclosing
context.
Listing 2.5 this in lambda expression
public class LambdaThis {
private String name = "Alex";
From code examples in Listing 2.4 and Listing 2.5, we can see how lambda expressions make
developers’ life much easier by simplifying the scope and name resolution.
Listing 2.6 Compilation error of using non-final variables in lambda expression body
@FunctionalInterface
public interface StringProducer {
String produce();
}
Static method
Refer to a static method using ClassName::methodName, e.g. String::format, Integer::max.
Instance method of a particular object
Refer to an instance method of a particular object using instanceRef::methodName, e.g.
obj::toString, str::toUpperCase.
Method from superclass
Refer to an instance method of a particular object’s superclass using super::methodName,
e.g. super::toString. In Listing 2.8, if replacing this::toString with super::toString,
then toString of Object class will be invoked instead of toString of StringProducerMain
class.
Instance method of an arbitrary object of a particular type
Refer to an instance method of any object of a particular type using ClassName::methodName,
e.g. String::toUpperCase. The syntax is the same as referring a static method. The difference
is that the first parameter of functional interface’s method is the invocation’s receiver.
Class constructor
Refer to a class constructor using ClassName::new, e.g. Date::new.
Array constructor
Refer to an array constructor using TypeName[]::new, e.g. int[]::new, String[]::new.
Lambda expressions 9
In the first version, interface RecordInserter only has one abstract method insert. SimpleRecordInserter
class in Listing 2.10 is the first implementation.
Listing 2.10 First implementation of RecordInserter interface
Then we find out that the performance of inserting a lot of records is not very good, so we want
to add batch inserting to improve performance. So a new method insertBatch is added to the
RecordInserter interface with default implementation. insertBatch takes a list of Record as
input, so the default implementation just iterates the list and uses existing insert method to insert
Record one by one. This default implementation can make sure SimpleRecordInserter class still
works.
Lambda expressions 10
Listing 5.1 shows a common pattern of writing code that takes arguments with possible null values.
If a method accepts multiple arguments, all these arguments should be checked. Utility methods like
Objects.requireNonNull() can help, but the code is still long and tedious. Another case is for
long object references chains, e.g. a.b.c, then all objects in the reference chain need to be checked.
Groovy has safe navigation operator² ?., but Java doesn’t the same thing.
Optional objects are very easy to create. If we are sure the actual object is not null, we can use
<T> Optional<T> of(T value) method to create an Optional object, otherwise we should use
<T> Optional<T> ofNullable(T value) method. If we just want to create an Optional object
which holds nothing, we can use <T> Optional<T> empty().
Listing 5.2. Create Optional objects
Listing 5.3 is similar with Listing 5.1, except it uses Optional. But the code in Listing 5.3 is still long
and tedious.
T orElse(T other) returns the value if it’s present, otherwise return the specified other object.
This other object acts as the default or fallback value.
Listing 5.5. Example of Optional.orElse
<U> Optional<U> map(Function<? super T,? extends U> mapper) applies the specified
mapping function to the Optional’s value if present. If the mapping result is not null, it returns an
Optional object with this mapping result, otherwise returns an empty Optional object.
flatMap() is very useful when handling long reference chain. For example, considering a Customer
class has a method getAddress() to return an Optional<Address> object. The Address class has
a method getZipCode() to return an Optional<ZipCode> object. Listing 5.10 uses two chained
flatMap() method invocations to get an Optional<ZipCode> object from an Optional<Customer>
object. With the use of flatMap(), it’s very easy to create safe chained object references.
Optional 15
3.3 How-tos
class C {
private String value = "Hello";
class B {
private C c = new C();
public Optional<C> getC() {
return Optional.ofNullable(c);
}
}
class A {
private B b = new B();
public Optional<B> getB() {
return Optional.ofNullable(b);
}
}
}
Suppose we want to retrieve a value to be used in the client code and we have different
types of retrievers to use, the code logic is that we try the first retriever first, then the second
retriever and so on, until a value is retrieved. In Listing 5.15, ValueRetriever is the interface of
retrievers with only one method retrieve() which returns an Optional<Value> object. Classes
ValueRetriever1, ValueRetriever2 and ValueRetriever3 are different implementations of the
interface ValueRetriever.
Listing 5.15 shows two different ways to chain method invocations. The first method retrieveResultOrElseGet()
uses Optional’s orElseGet() method to invoke a Supplier function to retrieve the value. The sec-
ond method retrieveResultStream() uses Stream.of() to create a stream of Supplier<Optional<Value>>
objects, then filters the stream to only include Optionals with values, then gets the first value.
Optional 18
Listing 5.15 Chain method invocations with return value of Optional objects in sequence
public class ChainedOptionals {
private ValueRetriever retriever1 = new ValueRetriever1();
private ValueRetriever retriever2 = new ValueRetriever2();
private ValueRetriever retriever3 = new ValueRetriever3();
class Value {
private String value;
public Value(String value) {
this.value = value;
}
@Override
public String toString() {
return String.format("Value -> [%s]", this.value);
}
}
Optional 19
interface ValueRetriever {
Optional<Value> retrieve();
}
@Override
public Optional<Value> retrieve() {
return Optional.empty();
}
}
@Override
public Optional<Value> retrieve() {
return Optional.of(new Value("hello"));
}
}
@Override
public Optional<Value> retrieve() {
return Optional.of(new Value("world"));
}
}
}
As streams are lazily evaluated, Supplier functions in Listing 5.15 won’t be invoked unless
the last Supplier function returns an empty Optional object. This can make sure that there
won’t be any unnecessary method invocations.
Starting from Java 9, you can use the Optional.stream() method in Java standard library.
3.3.6 How to use Optional to check for null and assign default
values?
It’s a common case to check if a value is null and assign a default value to it if it’s null. Optional
can be used to write elegant code in this case. Listing 5.17 shows the traditional way to check for
null which uses four lines of code.
Listing 5.18 shows how to use Optional to do the same thing as Listing 5.17with only one line of
code.
Listing 5.18 Use Optional to simplify code
¹https://leanpub.com/java8-lambda-expressions-streams