exploring streams and lambdas in java8

52
Exploring Streams and Lambdas in Java8 • Presented By:Isuru Samaraweera

Upload: isuru-samaraweera

Post on 15-Apr-2017

126 views

Category:

Technology


5 download

TRANSCRIPT

Page 1: Exploring Streams and Lambdas in Java8

Exploring Streams and Lambdas in Java8

• Presented By:Isuru Samaraweera

Page 2: Exploring Streams and Lambdas in Java8

Agenda• Why change Java again?• What is FP & Lambda?• Functional Interfaces• Streams• Reduction• Overloading Lambdas• Advanced Collections and collectors• Partioning and Grouping data• Data Parrellelism• Testing Lambdas

Page 3: Exploring Streams and Lambdas in Java8

Why change java again

• Rise of the multicore CPUS• Algorithms involves locks error-prone time

consuming• Util.concurrent libraries have limititaions• Lack of efficient parrelel operations on a

collection• Java8 allows complex collection-processing

algorithms

Page 4: Exploring Streams and Lambdas in Java8

What is fp

• Oop data abstraction/side efects• Functional focuses on side effect free• Pure functions/lambdas• Pass functions around easeir to write lazy code

which initialises values when necessary• n -> n % 2 != 0; • (char c) -> c == 'y';• (x, y) -> x + y; • (int a, int b) -> a * a + b * b;

Page 5: Exploring Streams and Lambdas in Java8

Functional Interfaces

• How does lambda expressions fit into Javas type system?

• Each lambda corresponds to a given type, specified by an interface

• exactly one abstract method declaration• Interface with single abstract method used as

type • Multiple optional default methods

Page 6: Exploring Streams and Lambdas in Java8

Define a functional interface@FunctionalInterfacepublic interface Calculator { abstract int calculate(int x,int y);}public class FPDemo {public static void main(String[] args) {Calculator f=(x,y)->(x+y);int z = f.calculate(3, 4);System.out.println(z);

test((p,q)->p*q);}public static int test(Calculator cal) {Return cal.calculate(4, 8);}

Page 7: Exploring Streams and Lambdas in Java8

Lambda Scopes

• int k=0;• Calculator c1=• (int x, int y)->• {System.out.println(k);return x+y;};• k=8;//fail to compile• K is implicitly final• Final is optional

Page 8: Exploring Streams and Lambdas in Java8

Important functional interfaces in Java

• public interface Predicate<T> { boolean test(T t); }• public interface Function<T,R> { R apply(T t); } • public interface BinaryOperator<T> { T apply(T left, T right); } public interface Consumer<T> { void accept(T t); } • public interface Supplier<T> {T get(); }

Page 9: Exploring Streams and Lambdas in Java8

Predicate• package com.java8.general;

• import java.util.Objects;• import java.util.function.Predicate;

• public class PredicateTest {

• public static void main(String[] args) {• Predicate<String> predicate = (s) -> s.length() > 0;• boolean s=predicate.test("foo"); // true• predicate.negate().test("foo");

• Predicate<Boolean> nonNull = Objects::nonNull;• Predicate<Boolean> isNull = Objects::isNull;

• Predicate<String> isEmpty = String::isEmpty;• Predicate<String> isNotEmpty = isEmpty.negate();• }

• }

Page 10: Exploring Streams and Lambdas in Java8

Functions

• Functions accept one argument and produce a result.

• Function<String, Integer> toInteger = Integer::valueOf;

• Function<String, Integer> toInteger=(s->Integer.valueOf(s);

Page 11: Exploring Streams and Lambdas in Java8

Suppliers• Suppliers produce a result of a given generic type. Unlike

Functions, Suppliers don't accept arguments.• public class SupplierTest {

• public static void main(String[] args) {

• Supplier<SupplierTest> personSupplier = SupplierTest::new;• personSupplier.get(); // new Person• }• }

Page 12: Exploring Streams and Lambdas in Java8

Consumers

• consumers represents operations to be performed on a single input argument.

• Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);

• greeter.accept(new Person("Luke", "Skywalker"));

Page 13: Exploring Streams and Lambdas in Java8

Comparators

• Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland");

• comparator.compare(p1, p2); // > 0

Page 14: Exploring Streams and Lambdas in Java8

Type inference

• Predicate<Integer> atleast5=x->x>5;

• BinaryOperator<Long> addlngs=(x,y)->x+y;

• BinaryOperator add=(x,y)->x+y;

Page 15: Exploring Streams and Lambdas in Java8

Streams

• A stream represents a sequence of elements and supports different kind of operations to perform computations upon those elements:

• List<String> myList =• Arrays.asList("a1", "a2", "b1", "c2", "c1");• myList.stream().filter(s -> s.startsWith("c"))• .map(String::toUpperCase) .sorted()• .forEach(System.out::println);

Page 16: Exploring Streams and Lambdas in Java8

Traditional external iteration

• Int count=0;• Iterator<Artist> iterator=allartists.iterator()• While(iterator.hasNext())• {Artist artist=iterator.next();• If(artist.isForm(“NY”)• Count++• }• Lot of boilerplate code and difficult concurrency• Serial drawback

Page 17: Exploring Streams and Lambdas in Java8

Internal Iterator with streams

• Long count=allartists.stream().filter(artist->artist.isFrom(“NY”)).count();

• Stream is tool for building up complex operations on collections using functional approach

• If return is a stream its lazy-Intermediete stream• If returns a value or void then its eager-Terminal

value

Page 18: Exploring Streams and Lambdas in Java8

Terminal vs Lazy operations• //does nothing• artlist.stream().filter(artist->artist.isFrom("India"));• //does nothing lazy inilitation• artlist.stream().filter(artist-

>{System.out.println(artist.getName());• return artist.isFrom("India");});• long x=artlist.stream().filter(artist-

>{System.out.println(artist.getName());• return artist.isFrom("India");}).count();

• System.out.println("x is"+x);

Page 19: Exploring Streams and Lambdas in Java8

Common stream operations

• Collect(toList())• Eager operation that genertes a list from the

values in a stream• List<String>

collected=Stream.of("A","b","c").collect(Collectors.toList());

• Streams are lazy so u need eager operation like collect

Page 20: Exploring Streams and Lambdas in Java8

map

• Traditional uppercase conversion• List<String> collected=new ArrayList<>();• For(String string:asList(“a”,”b”,”c”)){• String upper=string.toUpperCase();• Collected.add(upper);• }• List<String>

mapped=Stream.of("A","b","c").map(string->string.toUpperCase()).collect(Collectors.toList());

Page 21: Exploring Streams and Lambdas in Java8

filter

• Assume search strings start with a digit• Traditional style-For loop and iterate• Functional style• List<String>

begwithn=Stream.of(“a”,”1abc”,”abc1”).filter(value->isDigit(value.charAt(0))).collect(toList());

• Predicate interface returns true/false

Page 22: Exploring Streams and Lambdas in Java8

sorted

• stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);

• Sorted is an intermediate operation which returns a sorted view of the stream. The elements are sorted in natural order unless you pass a custom Comparator.

Page 23: Exploring Streams and Lambdas in Java8

Map and Match

• stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println);

• boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a"));

Page 24: Exploring Streams and Lambdas in Java8

flatmap

• Replace a value with a stream and concantenate all streams together

• List<Integer> together=Stream.of(Arrays.asList(1,2),Arrays.asList(3,4)).flatMap(numbers->numbers.stream()).collect(toList());

• Flatmap return type is a stream

Page 25: Exploring Streams and Lambdas in Java8

Max and min

• List<Track> tracks=Arrays.asList(new Track("track1",524),new Track("track2",454),new Track("track3",444));

• Track shortesttrack=tracks.stream().min(Comparator.comparing(track->track.getLength())).get();

• Comparing builds a comparator using keys

Page 26: Exploring Streams and Lambdas in Java8

Reduction Operations

• Terminal operations ( average, sum, min, max, and count) that return one value by combining the contents of a stream

• reduction operations that return a collection instead of a single value.

• general-purpose reduction operations reduce and collect

Page 27: Exploring Streams and Lambdas in Java8

ReduceOptional<T> reduce(BinaryOperator<T> accumulator)Performs a reduction on the elements of this stream, using

an associative accumulation function, and returns an Optional describing the reduced value, if any.

T reduce(T identity, BinaryOperator<T> accumulator)Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value.

<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions.

Page 28: Exploring Streams and Lambdas in Java8

Reduce with BinaryOperator

• persons• .stream()• .reduce((p1, p2) -> p1.age > p2.age ? p1 :

p2)• .ifPresent(System.out::println); • // Pamela• Returns Optional

Page 29: Exploring Streams and Lambdas in Java8

Reduce with identity and accumilator

• Integer totalAgeReduce = roster• .stream()• .map(Person::getAge)• .reduce(• 0,• (a, b) -> a + b); • identity: The identity element is both the initial value of the reduction and

the default result if there are no elements in the stream

• accumulator: The accumulator function takes two parameters: a partial result of the reduction (in this example, the sum of all processed integers so far) and the next element of the stream (in this example, an integer).

(a, b) -> a + b

Page 30: Exploring Streams and Lambdas in Java8

Generic reduce• a reduce operation on elements of type <T> yielding a result

of type <U>• <U> U reduce(U identity, BiFunction<U, ? super T, U>

accumulator, BinaryOperator<U> combiner);• identity element is both an initial seed value for the

reduction and a default result if there are no input elements• The accumulator function takes a partial result and the next

element, and produces a new partial result• The combiner function combines two partial results to

produce a new partial result.

Page 31: Exploring Streams and Lambdas in Java8

• List<String> test= new ArrayList<String>();• test.add("isuru");• test.add("sam");• test.add("silva");• int s = test.stream().reduce(0, (x, y) -> x + y.length(), (x, y) -> x + y);• - identity - identity value for the combiner function

- reducer - function for combining two results- combiner - function for adding an additional element into a result.

• When you run the stream in parallel, the task is spanned into multiple threads. So for example the data in the pipeline is partitioned into chunks that evaluate and produce a result independently. Then the combiner is used to merge this results.

Page 32: Exploring Streams and Lambdas in Java8

Putting all together

• Get all artists for album• Figure out which artists are bands• Find the nationalities for each band• Put together a set of these values

Page 33: Exploring Streams and Lambdas in Java8

• Set<String> origins=album.getMusicians().filter(artist->artist.getName().startsWith(“The”)).map(artist->artist.getNationality()).collect(toSet());

• Filter,map are lazy operations• Collect is eager

Page 34: Exploring Streams and Lambdas in Java8

Stream misuse• List<Artist> musicians=album.getMusicians().collect(toList());• List<Artist> bands=musicians.stream().filter(artist-

>artist.getName().startsWith(“The”)).collect(toList());• Set<String> origins=bands.stream.map(artist-

>artist.getNationality().collect(toSet());• Its harder to read /boiler plate code• Less efficient because it requires eagerly creating new collection

objects in each intermediate step• Clutters the code with intermediate variables• Multithreading/parrelllism issues• Chain them

Page 35: Exploring Streams and Lambdas in Java8

Overloading• private interface IntegerBiFunction extends

BinaryOperator<Integer>{}• public void overloadedm1(BinaryOperator<Integer> lambda)• {• System.out.println("Binaryoperator");• }

• public void overloadedm1(IntegerBiFunction lambda)• {• System.out.println("Bifunction");• }

Page 36: Exploring Streams and Lambdas in Java8

• public void test()• {• overloadedm1( (y,x)->x+1);• }• If there are several possible target types the

most specific type is inferred

Page 37: Exploring Streams and Lambdas in Java8

• private interface IntPredicate• {• public boolean test(int value);• }• public void overloadp1(Predicate<Integer> predicate)• {• System.out.println("Predicate");• }

• public void overloadp1(IntPredicate predicate)• {• System.out.println("Intpredicate");• }• If there are several possible target types and there is no specific type you have to manually

provid the type

Page 38: Exploring Streams and Lambdas in Java8

Binary interface compatibility

• Backward binary compatibility-If you compile app in Java1 to 7 it will run out of the box in Java8

• Stream method added to java8 Collection iface

• Breaks the binary compatibility• Not compile or Exception by Calssloader

Page 39: Exploring Streams and Lambdas in Java8

Advanced Collections and Collectors

• Method references• Artist:getName• Artist:new• String[] new

Page 40: Exploring Streams and Lambdas in Java8

Element Ordering

• List<Integer> numbers=Arrays.asList(2,3,4);• List<Integer>

sameOrder=numbers.stream().collect(Collectors.toList());

• Set<Integer> numberset=new HashSet<>(Arrays.asList(3,4,5,6));

• List<Integer> ntsameOrderset=numberset.stream().collect(Collectors.toList());

Page 41: Exploring Streams and Lambdas in Java8

Collector

• toList ,toSet you done give the complete implementation

• Colelcting values into a collection of specific type

• Stream.collec(toCollection(TreeSet ::new))

Page 42: Exploring Streams and Lambdas in Java8

To Values

• Collect into a single value using collector• Finding the band with most numbers• public Optional<Artist>

biggestGroup(Stream<Artist> artists)• {• Funtion<Artist,Long> getCount=artist-

>artist.getMembers().count();• Return artists.collect(maxBy(comparing(getCount)));• minBy also there

Page 43: Exploring Streams and Lambdas in Java8

Partioning the data

• Split out a list• Public Map<Boolean,List<Artist>>

bandsAndsolo(Stream<Artist> artists)• {• return artists.collect(partitionBy(artist-

>artist.isSolo()));• }• Or partitionBy(Artist::isSolo) method reference

Page 44: Exploring Streams and Lambdas in Java8

Grouping the data

• Grouping albums by main artist• Public Map<Artist,List<Album>>

albumsByArtists(Stream<Album> albums)• {• Return albums.collect(groupingBy(album-

>album.getMainMusician()));• }

Page 45: Exploring Streams and Lambdas in Java8

String• Traditional String handling• StringBuilder builder=new StringBuilder(“[“);• For(Artist artist:artists)• {• If(builder.length()>1)• Builder.apppend(“, “);• }• String name=artist.getName();• Builder.append(name);• }• Builder.append(“]”);• String result=builder.toString();

• String result=artists.stream().map(Artist::getName).collect(Collectors.joiniing(“, “, “[“,”]”));

Page 46: Exploring Streams and Lambdas in Java8

Composing collectors

• Naïve approach• Map<Artist,List<Album>>

albumByArtist=albums.collect(groupingBy(album->album.getMainMusician())));

• Map<Artist,Integer> numberofalbums=new HashMap<>();

• For(Entry<Artist,List<Album> entry:albumsByArtist.entrySet()){

• Numberofalbums.put(entry.getKey(),entry.getValue().size());

Page 47: Exploring Streams and Lambdas in Java8

Using collectors to count the number of albums for each artist

• Public Map<Artist,Long> numberOfalbums(Stream<Album> albums)

• {Return albums.collect(groupingBy(album->album.getMusician(),counting())));

• }• This grouping devides elements into buckets• Reduction as a collector

Page 48: Exploring Streams and Lambdas in Java8

Data paralleism

• Parellism vs Concurrency• Concurrency arises when 2 tasks are making

progress at overlapping time periods• Parrellism arises 2 tasks are hapenning at

same time –multicore cpu• In single cpu-concurrency• Multi core-concurrent/parrellel

Page 49: Exploring Streams and Lambdas in Java8

Data parellism..contd

• Splitting up the data to be operated on and assigning single processing unit to each chunk of data

• Perform same operation on a large dataset• Task parellism-each individual thread of

execution can be doing totally different task• Java EE container TP

Page 50: Exploring Streams and Lambdas in Java8

Parellel stream operations• Serial summing of album trak lengths• Public int serialArraySum(){• Return

album.stream().flatmap(Album::gettracks).mapToInt(track:getLength).sum();

• }• Public int parreelelArraySum(){• Return

albums.parallelstream().flatMap(Album::gettracks).mapToInt(Track::getLength).sum();

• When 10000 albums are hit parrel code is faster

Page 51: Exploring Streams and Lambdas in Java8

Testing Lambdas

• Public static List<String> allToUppercase(List<String> words)

• {

• Return words.stream().map(string->string.toUpperCase()).collect(Collectors.<String>.toList());

• }

Page 52: Exploring Streams and Lambdas in Java8

• @Test• Public void multiplewordsToUpperCase()• {• List<String> input=Arrays.asList(“a”,”b”,”hello”);• List<String> result=Testing.allToUppercase(input);• assertEquals(asList(“A”,”B”,”HELLO”),result);• }