Top Banner
Java 8 Streams Saint Louis Java Users Group 8 January, 2015 Charles A Sharp [email protected]
36

Charles Sharp: Java 8 Streams

Jul 12, 2015

Download

Software

jessitron
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Charles Sharp: Java 8 Streams

Java 8 StreamsSaint Louis Java Users Group

8 January, 2015

Charles A Sharp [email protected]

Page 2: Charles Sharp: Java 8 Streams

Java 8 StreamsSaint Louis Java Users Group

8 January, 2015

Charles A Sharp [email protected]

Auspicious

Page 3: Charles Sharp: Java 8 Streams

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

Page 4: Charles Sharp: Java 8 Streams
Page 5: Charles Sharp: Java 8 Streams

grep 'Error' /var/log/err_log | \

sed 's/^.*Error//' | \

sort | \

uniq -c > /tmp/error_count

Page 6: Charles Sharp: Java 8 Streams

— 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.”

Page 7: Charles Sharp: Java 8 Streams

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.

.

.

.

Page 8: Charles Sharp: Java 8 Streams

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)

Page 9: Charles Sharp: Java 8 Streams

Srsly. What is a Java 8 Stream?

Source

[IntermediateOperations.]*

TerminalOperation

Page 10: Charles Sharp: Java 8 Streams

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.

Page 11: Charles Sharp: Java 8 Streams

Streams-relevant Java 8 Review

Page 12: Charles Sharp: Java 8 Streams

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.

Page 13: Charles Sharp: Java 8 Streams

… 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.

Page 14: Charles Sharp: Java 8 Streams

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)

Page 15: Charles Sharp: Java 8 Streams

Method ReferenceEasy-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);

Page 16: Charles Sharp: Java 8 Streams

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).

Page 17: Charles Sharp: Java 8 Streams

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)

Page 18: Charles Sharp: Java 8 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)…

Page 19: Charles Sharp: Java 8 Streams

…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()

Page 20: Charles Sharp: Java 8 Streams

…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();

Page 21: Charles Sharp: Java 8 Streams

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)

Page 22: Charles Sharp: Java 8 Streams

Now that you have a Stream, what do you do with it?

• Transform

• Aggregate

• Find

• Reduce

Page 23: Charles Sharp: Java 8 Streams

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. …

Page 24: Charles Sharp: Java 8 Streams

First, the Original Codefor (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");

Page 25: Charles Sharp: Java 8 Streams

Then, the Streamified codereturn 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");

Page 26: Charles Sharp: Java 8 Streams

Intermediate Operations• map

• filter

• limit

• skip

• parallel

• sequential

— documented in java.util.stream.Stream

Page 27: Charles Sharp: Java 8 Streams

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

Page 28: Charles Sharp: Java 8 Streams

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);

Page 29: Charles Sharp: Java 8 Streams

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(). …

Page 30: Charles Sharp: Java 8 Streams

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);

Page 31: Charles Sharp: Java 8 Streams

Terminal Operations• forEach

• toArray, toList

• reduce

• collect

• min, max, count, sum

• anyMatch, allMatch, noneMatch

• findFirst, findAny

• iterator, spliterator

Page 32: Charles Sharp: Java 8 Streams

findFirst & findAny• short-circuit operations

• both return an Optional

• Example in Streamified Class code

Page 33: Charles Sharp: Java 8 Streams

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)));

Page 34: Charles Sharp: Java 8 Streams

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

Page 35: Charles Sharp: Java 8 Streams

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

Page 36: Charles Sharp: Java 8 Streams

“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