2. 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
3. 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
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
• 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
6. 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);
}
7. 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
8. 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();
}
10. Functions
• Functions accept one argument and produce a
result.
• Function<String, Integer> toInteger =
Integer::valueOf;
• Function<String, Integer> toInteger=(s-
>Integer.valueOf(s);
11. 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
• }
• }
12. 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"));
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
15. 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);
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 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
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
21. 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
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 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
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
• 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
27. 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.
29. 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
30. 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.
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
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
36. • public void test()
• {
• overloadedm1( (y,x)->x+1);
• }
• If there are several possible target types the
most specific type is inferred
37. • 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
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 and Collectors
• Method references
• Artist:getName
• Artist:new
• String[] new
41. Collector
• toList ,toSet you done give the complete
implementation
• Colelcting values into a collection of specific
type
• Stream.collec(toCollection(TreeSet ::new))
42. 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
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()));
• }
47. 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
48. 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
49. 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
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