Exploring Streams and Lambdas in Java8 • Presented By:Isuru Samaraweera
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
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
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;
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
Define a functional interface @FunctionalInterface public 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); }
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
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(); }
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(); • } • }
Functions • Functions accept one argument and produce a result. • Function<String, Integer> toInteger = Integer::valueOf; • Function<String, Integer> toInteger=(s- >Integer.valueOf(s);
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 • } • }
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"));
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
Type inference • Predicate<Integer> atleast5=x->x>5; • BinaryOperator<Long> addlngs=(x,y)->x+y; • BinaryOperator add=(x,y)->x+y;
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);
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
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
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);
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(Collec tors.toList()); • Streams are lazy so u need eager operation like collect
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());
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(v alue->isDigit(value.charAt(0))).collect(toList()); • Predicate interface returns true/false
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.
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"));
flatmap • Replace a value with a stream and concantenate all streams together • List<Integer> together=Stream.of(Arrays.asList(1,2),Arrays.a sList(3,4)).flatMap(numbers- >numbers.stream()).collect(toList()); • Flatmap return type is a stream
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
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
Reduce Optional<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.
Reduce with BinaryOperator • persons • .stream() • .reduce((p1, p2) -> p1.age > p2.age ? p1 : p2) • .ifPresent(System.out::println); • // Pamela • Returns Optional
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
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.
• 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.
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
• Set<String> origins=album.getMusicians().filter(artist- >artist.getName().startsWith(“The”)).map(arti st->artist.getNationality()).collect(toSet()); • Filter,map are lazy operations • Collect is eager
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
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"); • }
• public void test() • { • overloadedm1( (y,x)->x+1); • } • If there are several possible target types the most specific type is inferred
• 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
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
Advanced Collections and Collectors • Method references • Artist:getName • Artist:new • String[] new
Element Ordering • List<Integer> numbers=Arrays.asList(2,3,4); • List<Integer> sameOrder=numbers.stream().collect(Collectors.t oList()); • Set<Integer> numberset=new HashSet<>(Arrays.asList(3,4,5,6)); • List<Integer> ntsameOrderset=numberset.stream().collect(Coll ectors.toList());
Collector • toList ,toSet you done give the complete implementation • Colelcting values into a collection of specific type • Stream.collec(toCollection(TreeSet ::new))
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
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
Grouping the data • Grouping albums by main artist • Public Map<Artist,List<Album>> albumsByArtists(Stream<Album> albums) • { • Return albums.collect(groupingBy(album- >album.getMainMusician())); • }
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(“, “, “[“,”]”));
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.getVal ue().size());
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
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
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
Parellel stream operations • Serial summing of album trak lengths • Public int serialArraySum(){ • Return album.stream().flatmap(Album::gettracks).mapToInt(tr ack:getLength).sum(); • } • Public int parreelelArraySum(){ • Return albums.parallelstream().flatMap(Album::gettracks).ma pToInt(Track::getLength).sum(); • When 10000 albums are hit parrel code is faster
Testing Lambdas • Public static List<String> allToUppercase(List<String> words) • { • Return words.stream().map(string- >string.toUpperCase()).collect(Collectors.<Stri ng>.toList()); • }
• @Test • Public void multiplewordsToUpperCase() • { • List<String> input=Arrays.asList(“a”,”b”,”hello”); • List<String> result=Testing.allToUppercase(input); • assertEquals(asList(“A”,”B”,”HELLO”),result); • }

Exploring Streams and Lambdas in Java8

  • 1.
    Exploring Streams andLambdas in Java8 • Presented By:Isuru Samaraweera
  • 2.
    Agenda • Why changeJava again? • What is FP & Lambda? • Functional Interfaces • Streams • Reduction • Overloading Lambdas • Advanced Collections and collectors • Partioning and Grouping data • Data Parrellelism • Testing Lambdas
  • 3.
    Why change javaagain • 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
  • 4.
    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;
  • 5.
    Functional Interfaces • Howdoes 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
  • 6.
    Define a functionalinterface @FunctionalInterface public 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); }
  • 7.
    Lambda Scopes • intk=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
  • 8.
    Important functional interfacesin 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(); }
  • 9.
    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(); • } • }
  • 10.
    Functions • Functions acceptone argument and produce a result. • Function<String, Integer> toInteger = Integer::valueOf; • Function<String, Integer> toInteger=(s- >Integer.valueOf(s);
  • 11.
    Suppliers • Suppliers producea 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 • } • }
  • 12.
    Consumers • consumers representsoperations to be performed on a single input argument. • Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName); • greeter.accept(new Person("Luke", "Skywalker"));
  • 13.
    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
  • 14.
    Type inference • Predicate<Integer>atleast5=x->x>5; • BinaryOperator<Long> addlngs=(x,y)->x+y; • BinaryOperator add=(x,y)->x+y;
  • 15.
    Streams • A streamrepresents 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);
  • 16.
    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
  • 17.
    Internal Iterator withstreams • 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
  • 18.
    Terminal vs Lazyoperations • //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);
  • 19.
    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(Collec tors.toList()); • Streams are lazy so u need eager operation like collect
  • 20.
    map • Traditional uppercaseconversion • 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());
  • 21.
    filter • Assume searchstrings start with a digit • Traditional style-For loop and iterate • Functional style • List<String> begwithn=Stream.of(“a”,”1abc”,”abc1”).filter(v alue->isDigit(value.charAt(0))).collect(toList()); • Predicate interface returns true/false
  • 22.
    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.
  • 23.
    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"));
  • 24.
    flatmap • Replace avalue with a stream and concantenate all streams together • List<Integer> together=Stream.of(Arrays.asList(1,2),Arrays.a sList(3,4)).flatMap(numbers- >numbers.stream()).collect(toList()); • Flatmap return type is a stream
  • 25.
    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
  • 26.
    Reduction Operations • Terminaloperations ( 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
  • 27.
    Reduce Optional<T> reduce(BinaryOperator<T> accumulator)Performsa 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.
  • 28.
    Reduce with BinaryOperator •persons • .stream() • .reduce((p1, p2) -> p1.age > p2.age ? p1 : p2) • .ifPresent(System.out::println); • // Pamela • Returns Optional
  • 29.
    Reduce with identityand 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
  • 30.
    Generic reduce • areduce 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.
  • 31.
    • 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.
  • 32.
    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
  • 33.
  • 34.
    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
  • 35.
    Overloading • private interfaceIntegerBiFunction extends BinaryOperator<Integer>{} • public void overloadedm1(BinaryOperator<Integer> lambda) • { • System.out.println("Binaryoperator"); • } • public void overloadedm1(IntegerBiFunction lambda) • { • System.out.println("Bifunction"); • }
  • 36.
    • public voidtest() • { • overloadedm1( (y,x)->x+1); • } • If there are several possible target types the most specific type is inferred
  • 37.
    • private interfaceIntPredicate • { • 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
  • 38.
    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
  • 39.
    Advanced Collections andCollectors • Method references • Artist:getName • Artist:new • String[] new
  • 40.
    Element Ordering • List<Integer>numbers=Arrays.asList(2,3,4); • List<Integer> sameOrder=numbers.stream().collect(Collectors.t oList()); • Set<Integer> numberset=new HashSet<>(Arrays.asList(3,4,5,6)); • List<Integer> ntsameOrderset=numberset.stream().collect(Coll ectors.toList());
  • 41.
    Collector • toList ,toSetyou done give the complete implementation • Colelcting values into a collection of specific type • Stream.collec(toCollection(TreeSet ::new))
  • 42.
    To Values • Collectinto 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
  • 43.
    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
  • 44.
    Grouping the data •Grouping albums by main artist • Public Map<Artist,List<Album>> albumsByArtists(Stream<Album> albums) • { • Return albums.collect(groupingBy(album- >album.getMainMusician())); • }
  • 45.
    String • Traditional Stringhandling • 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(“, “, “[“,”]”));
  • 46.
    Composing collectors • Naïveapproach • 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.getVal ue().size());
  • 47.
    Using collectors tocount 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
  • 48.
    Data paralleism • Parellismvs 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
  • 49.
    Data parellism..contd • Splittingup 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
  • 50.
    Parellel stream operations •Serial summing of album trak lengths • Public int serialArraySum(){ • Return album.stream().flatmap(Album::gettracks).mapToInt(tr ack:getLength).sum(); • } • Public int parreelelArraySum(){ • Return albums.parallelstream().flatMap(Album::gettracks).ma pToInt(Track::getLength).sum(); • When 10000 albums are hit parrel code is faster
  • 51.
    Testing Lambdas • Publicstatic List<String> allToUppercase(List<String> words) • { • Return words.stream().map(string- >string.toUpperCase()).collect(Collectors.<Stri ng>.toList()); • }
  • 52.
    • @Test • Publicvoid multiplewordsToUpperCase() • { • List<String> input=Arrays.asList(“a”,”b”,”hello”); • List<String> result=Testing.allToUppercase(input); • assertEquals(asList(“A”,”B”,”HELLO”),result); • }