Java 8 Streams

28
Java 8 Streams J8S 1.2.1 (22.04.2022) Björn Kimminich https://twitter.com/bkimminich https://linkedin.com/in/bkimminich https://google.com/+BjörnKimminich http://slideshare.net/BjrnKimminich/

description

This is a brief introduction to "Java 8 Streams" featuring: * Bulk Operations * Lambda Expressions * Method References * Functional Operations * Collectors * ... Accompanying source code and examples can be found on https://github.com/bkimminich/java8-streams

Transcript of Java 8 Streams

Page 1: Java 8 Streams

Java 8 Streams

J8S 1.2.1 (10.04.2023)

Björn Kimminich

https://twitter.com/bkimminichhttps://linkedin.com/in/bkimminichhttps://google.com/+BjörnKimminichhttp://slideshare.net/BjrnKimminich/

Page 2: Java 8 Streams

Agenda

•Java 8•Streams•Lambdas•Method

References

Introduction

•Intermediate vs. Terminal

•Stateless vs. Stateful

•Short-Circuiting

•Collectors

Stream Operations

Page 3: Java 8 Streams

Java 8

Page 4: Java 8 Streams

Java™ SE 8 Release Contents

JSR 308: Annotations on Java TypesJSR 310: Date and Time APIJSR 335: Lambda Expressions

closuresJEP 107: Bulk Data Operations for Collections

for-eachfiltermapreduce http://www.jcp.org/en/jsr/detail?id=337

http://openjdk.java.net/jeps/107

Page 5: Java 8 Streams

Streams

Page 6: Java 8 Streams

Streams

interface java.util.stream.Stream<T>forEach()filter()map()reduce()…

java.util.Collection<T>Stream<T> stream()Stream<T> parallelStream()

Page 7: Java 8 Streams

Creating and using a Stream

List<Book> myBooks = …;

Stream<Book> books = myBooks.stream();

Stream<Book> goodBooks =books.filter(b -> b.getStarRating() > 3);

goodBooks.forEach(b -> System.out.println(b.toString()));

Page 8: Java 8 Streams

Properties of Streams

Streams do not store elements……they are a view on top of a data structure

Operations provided by Streams...…are applied to the underlying data source elements

Stream Operations can take as a parameter…

…Lambda expressions…Method references

Manipulating the underlying data source...

…will yield a ConcurrentModificationException

Page 9: Java 8 Streams

Lambdas

Page 10: Java 8 Streams

What are Lambda Expressions?

Java‘s version of ClosuresAllow to create (sort of) First Class Functions

Can be passed as a parameterCan be a return valueCan be stored in a variable

Target type is inferred from context

Why „sort of“?Because Java doesn‘t have a real function type!Java converts Lambdas into Functional Interfaces

Page 11: Java 8 Streams

Functional Interface

Functional Interface = Interface w/ 1 MethodNames of Interface and Method are irrelevantDefault: java.util.function.Consumer<T>

public interface Stream<T> {     void forEach(Consumer<? super T> consumer); } public interface Consumer<T> {void accept(T t);}

Consumer<Book> reduceRankForBadAuthors =   (Book b) -> { if (b.getStarRating() < 2) b.getAuthor().addRank(-1); };

books.forEach(reduceRankForBadAuthors);

books.forEach(b -> b.setEstimatedReadingTime(90*b.getPages()));

Page 12: Java 8 Streams

Lambda Syntax

/* argument list */ (int x, int y) -> { return x*y; } (x, y) -> { return x*y; } x -> { return x*2; }

() -> { System.out.println("Do you think this will work?"); }

/* single expression */ b -> { b.getMissingPages() > threshold ? b.setCondition(BAD)

: b.setCondition(GOOD) }

/* list of statements */ b -> {     Condition c = computeCondition(b.getMissingPages());     b.setCondition(c); }

Page 13: Java 8 Streams

Method References

Page 14: Java 8 Streams

Method References

books.forEach(b -> b.fixSpellingErrors()); books.forEach(Book::fixSpellingErrors); // instance method

books.forEach(b -> BookStore.generateISBN(b)); books.forEach(BookStore::generateISBN); // static method

books.forEach(b -> System.out.println(b.toString())); books.forEach(System.out::println); // expression

Stream<ISBN> isbns1 = books.map(b -> new ISBN(b)); Stream<ISBN> isbns2 = books.map(ISBN::new); // constructor

Page 15: Java 8 Streams

Intermediate vs. TerminalStream Operations

Page 16: Java 8 Streams

Intermediate vs. Terminal

Intermediate: Output is another Stream

filter()map()…

Terminal: Do something else with the Stream

forEach()reduce()…double totalPrice = books.mapToDouble(Book::getPrice)

               .reduce(0.0, (p1, p2) -> p1+p2);

Page 17: Java 8 Streams

Stream Evaluation

Intermediate Streams are not evaluated…

…until a Terminal Operation is invoked on them

Intermediate = LazyTerminal = Eager (Consuming)

This allows Java to……do some code optimization during compilation…avoid buffering intermediate Streams…handle parallel Streams more easily

Page 18: Java 8 Streams

Terminal = Consuming Operations

books.forEach(b -> System.out.println("Book: " + b.getTitle())); double totalPrice = books.reduce(0.0, (b1, b2)

-> b1.getPrice() + b2.getPrice());

Exception in thread "main" java.lang.IllegalStateException:     stream has already been operated upon or closed

Intermediate Operations can be chainedOnly one Terminal Operation can be invokedBest avoid reference variables to Streams entirely by using Fluent Programming

Construction (Intermediate)* Terminal;

Page 19: Java 8 Streams

Stateless vs. StatefulStream Operations

Page 20: Java 8 Streams

Stateless Intermediate Operations

Operation need nothing other than the current Stream element to perform its workExamples

map() Maps element to something elsefilter() Apply predicate and keep or drop elementList<Book> myBooks = ...;

double impairments = myBooks.stream().filter(b -> b.getCondition().equals(BAD))

                   .mapToDouble(Book::getPrice)                    .reduce(0.0, (p1, p2) -> p1 + p2);

Page 21: Java 8 Streams

Stateful Intermediate Operations

Operations that require not only the current stream element but also additional state

distinct() Element goes to next stage if it appears the first timesorted() Sort elements into natural ordersorted(Comparator) Sort according to provided Comparatorsubstream(long) Discard elements up to provided offsetsubstream(long, long) Keep only elements in between offsetslimit(long) Discard any elements after the provided max. size

myBooks.stream().map(Book::getAuthor).distinct().forEach(System.out::println);

Page 22: Java 8 Streams

Short-CircuitingStream Operations

Page 23: Java 8 Streams

Short-Circuiting Operations

Processing might stop before the last element of the Stream is reached

Intermediatelimit(long)substream(long, long)

TerminalanyMatch(Predicate)allMatch(Predicate)noneMatch(Predicate)findFirst()findAny()

Author rp = new Author("Rosamunde Pilcher");

boolean phew = myBooks.stream()                 .map(Book::getAuthor)                 .noneMatch(isEqual(rp));

System.out.println("Am I safe? " + phew);

Page 24: Java 8 Streams

Collectors

Page 25: Java 8 Streams

Collectors

<R> R collect(Collector<? super T, A, R> col)

Collect the elements of a Stream into some other data structurePowerful and complex toolCollector is not so easy to implement, but…

…luckily there are lots of factory methods for everyday use in java.util.stream.Collectors

toList()toSet()toCollection(Supplier)toMap(Function, Function)…

Page 26: Java 8 Streams

Collector Examples

List<Author> authors = myBooks.stream().map(Book::getAuthor)

         .collect(Collectors.toList());

double averagePages = myBooks.stream()          

.collect(Collectors.averagingInt(Book::getPages));

Page 27: Java 8 Streams

Joining Collector

Used for concatenation of CharSequencesInternally implemented using StringBuilder

A lot more efficient than a Map-Reduce with intermediately concatenated Strings

// not efficient due to recursive String concatenation. And ugly. String titleList = myBooks.stream().map(Book::getTitle).reduce("", (t1, t2) -> t1+t2);

// Still inefficient. Still ugly (initial line break)titleList = myBooks.stream().map(Book::getTitle).reduce("", (t1, t2) -> t1+"\n"+t2);

// more efficient thanks to StringBuilder. Pretty printed. titleList = myBooks.stream().map(Book::getTitle).collect(Collectors.joining("\n"));

Page 28: Java 8 Streams

Thank you…

…for your attention!

All code examples: https://github.com/bkimminich/java8-streams