Java 8 Streams
Saint Louis Java Users Group
8 January, 2015
Charles A Sharp
csharp@ociweb.com
Java 8 Streams
Saint Louis Java Users Group
8 January, 2015
Charles A Sharp
csharp@ociweb.com
Auspicious
While adding lambda expressions to the language is a
huge step forward, developers get their work done
every day by using the core libraries, so the language
evolution effort was paired with a library evolution effort
so that users could start using the new features on day
one. The centerpiece of the new library features is the
Stream abstraction, which provides powerful facilities
for aggregate operations on data sets, and has been
deeply integrated with the existing collection classes as
well as other JDK classes.
— State of the Lambda: Library Edition
Summary
grep 'Error' /var/log/err_log | 
sed 's/^.*Error//' | 
sort | 
uniq -c > /tmp/error_count
— Jennifer Egan, A Visit from the Goon Squad
“There are so many ways to go wrong," Lulu
said. "All we've got are metaphors, and
they're never exactly right. You can't ever just
Say. The. Thing.”
So.
What are we talking about?
In computer science, a stream is a sequence of data
elements made available over time.
https://en.wikipedia.org/wiki/Stream_(computing)
In object-oriented programming, input streams are
generally implemented as iterators.
.
.
.
Iterators? Say, what?
Well, no. I mean, yes.
In the Scheme language and some others, a stream is a
lazily evaluated or delayed sequence of data elements. A
stream can be used similarly to a list, but later elements
are only calculated when needed. Streams can therefore
represent infinite sequences and series.
https://en.wikipedia.org/wiki/Stream_(computing)
Srsly.
What is a Java 8 Stream?
Source
[IntermediateOperations.]*
TerminalOperation
Streams vs. Collections
• No Storage — carry values from a source.
• Functional in nature — do not modify the source.
• Laziness-seeking — efficient short-circuits.
• Stream operations are divided into intermediate (Stream-
producing) operations and terminal (value- or side-effect-
producing) operations. Intermediate operations are always
lazy.
• Possibly unbounded — A stream need not be finite, unlike a
collection.
• Consumable — one time only.
Streams-relevant
Java 8 Review
Functional Interface…
• Functional interfaces provide target types for lambda
expressions and method references. Each functional
interface has a single abstract method, called the
functional method for that functional interface, to
which the lambda expression's parameter and return
types are matched or adapted.
• The type of the functional interface is inferred from the
context and is known as the target type.
… Functional Interface
• @FunctionalInterface
An annotation that indicates an interface type
declaration is intended to be a functional interface.
(… However, the compiler will treat any interface
meeting the definition of a functional interface as a
functional interface regardless of whether or not a
FunctionalInterface annotation is present on the
interface declaration.)
• Functional Interfaces in Java 8 are listed in the
package description of java.util.function.
Function Shapes
• Function<T, R> (unary function from T to R)
• Consumer<T> (unary function from T to void)
• Predicate<T> (unary function from T to boolean)
• Supplier<R> (nilary function providing R)
• UnaryOperator<T> (a function from T to T)
• BinaryOperator<T, T> (a function from (T,T) to T)
Method Reference
Easy-to-read Lambda expression for a named method.
For example:
someStream.forEach(e -> { System.out.println(e)});
or:
someStream.forEach(System.out::println);
someStream.toArray(size -> new T[size]);
or:
someStream.toArray(T[]::new);
Optional
• A container object which may or may not contain a
non-null value. If a value is present, isPresent() will
return true and get() will return the value.
• Additional methods that depend on the presence or
absence of a contained value are provided, such as
orElse() (return a default value if value not present) and
ifPresent() (execute a block of code if the value is
present).
Spliterator
• An object for traversing and partitioning elements of a
source.
• A spliterator is the parallel analogue of an Iterator; it
describes a (possibly infinite) collection of elements,
with support for sequentially advancing, bulk traversal,
and splitting off some portion of the input into another
spliterator which can be processed in parallel. At the
lowest level, all streams are driven by a spliterator.
(from java.util.streams)
Creating Streams…
Must have a Source! Streams have no data of their own:
• Collections (Collection interface)
List<T> myList = …;
myList.stream()…;
myList.parallelStream() …;
• Arrays:
T[] myArray = …;
Arrays.stream(myArray)…
// alternatively …
Stream.of(myArray)…
…Creating Streams…
Retrofitted JDK classes:
• BufferedReader.lines() — lines of a file
• Files.lines(Path file) — lines of a file
• Files.list(Path dir) — file paths contained in dir
• Random.ints()
• BitSet.stream()
• Pattern.splitAsStream(java.lang.CharSequence)
• JarFile.stream()
…Creating Streams…
• Individual Values:
T t1;
T t2;
T t3;
Stream.of(t1, t2, t3)…
• Stream.Builder
Stream.Builder<String> sb = Stream.builder();
sb.accept(s1);
sb.accept(s2);
Stream<String> s = sb.build(). …;
or
Stream<String> s =
Stream.<String>builder().add(s1).add(s2).build();
Creating Streams…
• String:
String myName…
// produces an IntStream of code points
String.chars()…
• Generator functions:
//Infinite unordered Stream
Stream.generate(Supplier<T> s)
Stream.iterate(T seed, UnaryOperator<T> f)
Now that you have a Stream,
what do you do with it?
• Transform
• Aggregate
• Find
• Reduce
I'm bored.
Where's the code?
(from State of the Lambda: Libraries Edition — slightly edited)
[The following] is a fragment from the JDK class, Class (the
getEnclosingMethod method), which loops over all declared
methods, matching method name, return type, and number and
type of parameters. …
First, the Original Code
for (Method m : enclosingInfo.getEnclosingClass().getDeclaredMethods()){
if (m.getName().equals(enclosingInfo.getName()) ) {
Class<?>[] candidateParamClasses = m.getParameterTypes();
if (candidateParamClasses.length == parameterClasses.length) {
boolean matches = true;
for (int i = 0; i < candidateParamClasses.length; i++) {
if (!candidateParamClasses[i].equals(parameterClasses[i])) {
matches = false;
break;
}
}
if (matches) { // finally, check return type
if (m.getReturnType().equals(returnType))
return m;
}
}
}
}
throw new InternalError("Enclosing method not found");
Then, the Streamified code
return
Arrays.stream(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.orElseThrow(() -> new InternalError("Enclosing method not found");
Intermediate Operations
• map
• filter
• limit
• skip
• parallel
• sequential
— documented in java.util.stream.Stream
map
(mapToInt, mapToDouble, flatMap)
• Stream<R> map(Function<? super T,? extends R> mapper)
• The mapper function is applied to each element of the
stream and returns a Stream consisting of the results.
• Example:
Stream<String> shaggyLines = …
List<String> trimmedLines =
shaggyLines.map(String::trim)
.collect(toList);
• Example2: See Grep.java for flatmap
filter
• Stream<T> filter(Predicate<? super T> predicate)
• Returns a stream consisting of the elements of this stream that
match the given predicate.
• Example:
IntStream.range(1, 100)
.filter( e -> ((e % 5 == 0) || (e % 3 == 0)) )
.mapToObj( e -> { return
(e % 15 == 0) ? "FizzBuzz" :
(e % 5 == 0) ? "Buzz" :
"Fizz" ; } )
.forEach(System.out::println);
parallel & sequential
• parallel() — returns an equivalent stream that is parallel,
maybe
• sequential() - returns an equivalent stream that is sequential
• Example:
IntStream.range(0, 100)
.parallel().
…
limit & skip
• limit(long maxSize) — limits a stream to this number of
elements
• skip(long count) — skips over that many elements
• Example:
Stream.iterate(2, n -> n + 2)
.limit(10)
.skip(4)
.forEach(System.out::println);
Terminal Operations
• forEach
• toArray, toList
• reduce
• collect

• min, max, count, sum
• anyMatch, allMatch, noneMatch
• findFirst, findAny
• iterator, spliterator
findFirst & findAny
• short-circuit operations
• both return an Optional
• Example in Streamified Class code
collect
• The argument to collect() is a Collector, which embodies a recipe for folding
elements into a data structure or summary.
• The following will accumulate strings into an ArrayList:
List<String> asList = stringStream.collect(Collectors.toList());
• The following will classify Person objects by city:
Map<String, List<Person>> peopleByCity =
personStream.collect(Collectors.groupingBy(Person::getCity));
• The following will classify Person objects by state and city, cascading two
Collectors together:
Map<String, Map<String, List<Person>>> peopleByStateAndCity =
personStream.collect(Collectors.groupingBy(Person::getState,
Collectors.groupingBy(Person::getCity)));
Read these!
State of the Lambda
September 2013
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
State of the Lambda: Libraries Edition
September, 2013
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-libraries-final.html
Package description for java.util.stream
Java™ Platform Standard Ed. 8
http://docs.oracle.com/javase/8/docs/api/index.html
References
• Marty Hall's Java 8 Tutorials:
http://www.coreservlets.com/java-8-tutorial/
• Faster parallel processing in Java using Streams and a
spliterator, Marko Topolnik, PhD. :
https://www.airpair.com/java/posts/parallel-
processing-of-io-based-data-with-java-streams
• Processing Data with Java SE 8 Streams, Part 1,Raoul-
Gabriel Urma:
http://www.oracle.com/technetwork/articles/java/
ma14-java-se-8-streams-2177646.html
“You can know the name of a bird in all the
languages of the world, but when you're finished,
you'll know absolutely nothing whatever about
the bird… So let's look at the bird and see what
it's doing — that's what counts. I learned very
early the difference between knowing the name
of something and knowing something.”
— Richard Feynman