functional programming in jdk8

45
Programming – A Hands On Introduction To JDK 8 Bansilal Haudakari Technology Evangelist

Upload: bansilal-haudakari

Post on 13-Feb-2017

39 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Functional Programming In Jdk8

Functional Programming – A Hands On

Introduction To JDK 8

Bansilal Haudakari

Technology Evangelist

Page 2: Functional Programming In Jdk8

About Me Seasoned Programmer writing Code since Jdk1.0

Experienced developing software products for FX Trading, Content Management, IP Address Management, EAI at Citi, Oracle, Boeing and Intuit

Core Technologist at heart and believes in innovation culture

Passionate about building next generation products and platforms

Page 3: Functional Programming In Jdk8

Agenda Evolution of JAVA Functions Are First Class Citizens Your First Lambda with Uncle SAM Paradigm Shift In Programming : from

Imperative to Functional Lambda Under The Hood : Welcome Indy Streams

- Efficiency Of Streams – Lazy EvaluationJava 8 Best PracticesReactive Programming

Page 4: Functional Programming In Jdk8

Java Evolution

Evolution Of Java

Evolution Of Java

Page 5: Functional Programming In Jdk8

Evolution Of Java Jdk1 : Statically Type : Type of all variables is known or inferred at Compile Time Threading

Jdk5 Generics : provide compile-time type safety to catch invalid types Annotations

Jdk 8 Type Inference : compiler’s ability to look at each method invocation &

corresponding declaration to determine type argument /args that makes invocation applicable. Finally inference algo i.e. indy determines the most specific type

Indy Streams

Page 6: Functional Programming In Jdk8

What Is FP (Functional Programming)?• FP deals with code in the same way as data. This means

that a function should be a first-class value and able to be assigned to variables, passed to functions and so forth.

• Programs are written in terms of functions that always return the same output for a given input (regardless of any other state present in the running program) and that do not cause  any other effects or change any program state. Functions that obey this are sometimes called "pure" functions, and they behave in the same way that mathematical functions do.

• pure functions does not depend on external state & can easily be combined together - strong functional heritage

Page 7: Functional Programming In Jdk8

Examples of FPClojure function, e.g. log-processing function shown below, is

a first-class citizen, and doesn’t need to be bundled up in a class to exist.

(defn build-map-http-entries [log-file] (group-by :uri (scan-log-for-http-entries log-file)))

Scala permits functions as values, such as:val sqFn = (x: Int) => x * x

whilst retaining class and object syntax that is very close to that of Java.

Page 8: Functional Programming In Jdk8

Functions Are First Class Citizens In OOP Pass Objects to methods Create Objects within methods Return Objects from within methods

In FP: Pass Functions to functions Create Functions within functions Return Functions from functions

Page 9: Functional Programming In Jdk8

How Functional Is Java ?• Classes are the heart of the Java platform - a class is the basic

unit of functionality that the Java platform will load, link - and all code that is intended for execution must live inside a class.

• Interfaces can't be instantiated directly, and instead a class must be defined that implements the API defined by the interface.

• Arrays hold either primitive types, or instances of classes, or other arrays.

• The primitive types are all defined by the platform.

Page 10: Functional Programming In Jdk8

How Functional Is Java ?• Strongly type PL : Types are either reference types or primitive

types. Reference types are classes, interfaces or arrays. • Every type must have a name that it can be referred by. Even

the so-called "anonymous inner classes" still have a type by which the programmer must refer to them - the type of the interface that they implement:

Runnable r = new Runnable() { public void run() { System.out.println("Hello World!"); } };

• Another way of saying this is that every value in Java is either a primitive or an instance of some class.

Page 11: Functional Programming In Jdk8

Java 5 Type System• 3 major features to the type system - enums, annotations and generic types.• Enumerated types (enums) are similar to classes in some respects, but they have

the property that only a specified number of instances may exist, and each instance is specified in the class description and distinct. Intended primarily as a "typesafe constant" rather than the then-common practice of using small integers for constants, the enum construction also permits additional patterns that are sometimes extremely useful.

• Annotations are related to interfaces - the keyword to declare one is @interface - with the initial @ indicating that this is an annotation type. As the name suggests, they're used to annotate elements of Java code with additional information that doesn't affect behavior. Previously, Java had made use of "marker interfaces" to provide a limited form of this metadata, but annotations are considerably more flexible.

• Java's generics provide parameterized types - the idea that one type can act as a "container" for objects of another type, without regard for the specifics of exactly which type is being contained. The type that fits into the container is often called the type parameter.

Page 12: Functional Programming In Jdk8

Java 8 Type System• Is it still a Named type system? Here is an example from Java 8:

() -> { System.out.println("Hello World!"); }

This is a method, without a name, that takes no parameters and returns void. It's still perfectly statically typed, but is now anonymous.

Have we escaped the Kingdom of the Nouns? Is this actually a new form of type for Java?Answer : No.

The JVM, on which Java and other languages run, is very strictly tied to the concept of classes. Class loading is central to the Java platform's security and verification modes.

So, it would be very, very difficult to conceive of a type that was not, in some way, represented through a class

Page 13: Functional Programming In Jdk8

Lambda ExpressionsThanks to Uncle SAM

Sum(x,y) -> x +y(x,y) -> x +y

Page 14: Functional Programming In Jdk8

Your First Lambda Expression

new Thread(new Runnable() {

@Overridepublic void run() {

System.out.println("It runs !"); }}).start();

new Thread(() -> { System.out.println("It runs !"); }).start();

Page 15: Functional Programming In Jdk8

Lambda Expression A Lambda expression is an anonymous functions – Which are like methods but not associated with a class

() -> { System.out.println("It runs !"); } Syntax: ( parameters ) -> { lambda-body }

Where “->” is a Lambda Operator

Rules: Lambdas with a

– single parameter do not need brackets – no parameters must have empty brackets– Single line Lambdas do not need braces or explicit return statement– Body of the Lambda may throw exceptions

Simple Rule : Brackets and braces are optional for certain situations

Page 16: Functional Programming In Jdk8

Examples of Lambda Expression () -> System.out.println("Hello Lambda Expression")

x -> x + 10

(int x, int y) -> { return x + y; }

(String x, String y) -> x.length() – y.length()

x -> { if((x % 2)==0)

return "even" else

return "odd" }

Page 17: Functional Programming In Jdk8

Where to Use Lambda Expression A Lambda expression can be used wherever the type is a Functional Interface

– This is a single abstract method type SAM

– The Lambda expression provides the implementation of the single abstract method

– The OfficeSpace pattern where Mr Ted says i take the business reqmts and give it to programmers for execution

Page 18: Functional Programming In Jdk8

Paradigm Shift : Imperative To FunctionalList<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);for(int i = 0; i < numbers.size(); i++) { System.out.println(i); } JDK5: for(int e : numbers) { System.out.println(e); }

How does this code looks to you?

• Simple !!!

• Its Familiar but Not Simple because it has code smells !!!!

Page 19: Functional Programming In Jdk8

Code Smells• Imperative – saying How • Mutability – moving parts: starts with an int “I” value and then increment “I” and check

boundary limits so the focus is more on moving parts that means more errors & bugs in the code when the volume of mutation is more.

hard to make concurrent as well;

so lets refactor it into declarative style where the focus is not on How but on What and on Immutability as they are really powerful and also its functional style

Page 20: Functional Programming In Jdk8

Functional ProgrammingV1(Version 1) : similar to what we have done before. Consumer is new Functional Interface which has an accept method which takes a value

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

numbers.forEach( (Integer number) -> System.out.println(number); });

• Note methods like forEach work on Collections; takes specific Functional Interface as an argument e.g. Consumer

• Functional Interface defines the contract for number of parameters. For example if you send more than one parameter you get compilation error.

Page 21: Functional Programming In Jdk8

Functional ProgrammingV2 (Version 2) :

numbers.forEach((Integer number) -> System.out.println(number)); Type Inference V3(Version 3): Obvious : Life Lesson Obvious : You knows It, Java Knows It, So Why bother declare the Type. Java is finally Intelligent !! Note: Type Inference is ONLY for lambda expressions

numbers.forEach(number -> System.out.println(number));

Method Reference V4 (Version 4): numbers.forEach(System.out::println);

Page 22: Functional Programming In Jdk8

Lambda A Peek Under The HoodAre Lambda’s converted to Anonymous Inner Classes At Compile Time??Illusion Syntax Sugar? Compiler replace Lambda with Anonymous Inner class. Lets examine Step 1 : Write a Sample.java with anonymous inner class e.g. new Consumer and

compile it . You will see two .class files generated

Step 2 : Replace the anonymous inner class with lambda expression and compile it . You will see single .class files generated.

Repeat Step 1 with multiple copy/paste snippet of anonymous inner class. You will see multiple .class files generated

Repeat Step 2 with multiple copy/paste snippet of lambda expression. You will see single .class files generated.

So what’s really happening here?Its something Amazingly Cool !!! Lets see how

Page 23: Functional Programming In Jdk8

Welcome Indy$ javap -c HelloLambda //disassembles a .class file into readable formatpublic class HelloLambda { public HelloLambda(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return}

invokedynamic

Page 24: Functional Programming In Jdk8

Who is Indy ? Indy is invokedynamic i.e. invoke + dynamic Introduced in Jdk7 as a feature implemented for dynamically type

languages e.g. Scala, Jruby A Bytecode JIT level Optimization. Rewrote in Jdk8 to support use case of lambda expressions : no

longer anonymous inner classes Lambda Expression does not get replaced by Anonymous Inner

Classes i.e. they do not have the overhead of creating/deleting /GC Anonymous Objects. Reduced Runtime Memory Foot-Print !!

Life Lesson : Act of karma : if you do good things to others it will comes back to you

Page 25: Functional Programming In Jdk8

How Indy works?• Attach & de-attach to a function you want to invoke dynamically and

re-attach at runtime : call site function• Function Pointers are available at the JVM level for us to program

How is it implemented? When you create lambda expression, the call to Lambda Expression

will simply become invoke dynamic and the lambda expression itself will be one of the 3 based on the context:

A static method A instance method A routing for invoke dynamic method to another method in existing

class

Page 26: Functional Programming In Jdk8

StreamsThe Real Power House of Java 8

Page 27: Functional Programming In Jdk8

Streamsstream():- Operates on collection of values- A fancy iterator which gives many number of functions unlike

older iterator hasNext();- Interface to process collection of data- Express aggregation and reduction- Facilitate operation pipelining on bulk data

Streams include:Lambda operators (map,filter, sort, projections, etc) Terminal operators (collect, reduce, forEach, min, max, etc)Streams are lazily executed (at terminal operator)

Page 28: Functional Programming In Jdk8

Map the Streams - map() : Transforms Values - A map applies a function to input element and gives output element similar to

mathematical function which transforms input to output

- Number of elements in the Input = Number of elements in the Output e.g. I need the names of all the people in the room i.e. names = number of people

- But no guarantee on the type of output w.r.t input for e.g. I need the phone numbers of all the people in the room so its mapping of Name to Phone#

- Example : map( e -> e*2) of same type ; map( e -> e*2.0) – transformation type

- Syntax : Parameter of Stream<T> coming in as Input ; map applies a Function<T, R> to a input stream of type <T> and returns a stream of type R Stream<R>

Page 29: Functional Programming In Jdk8

DemoImperative:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); int totalOfValuesDoubled = 0; for(int number : numbers) { totalOfValuesDoubled += number * 2; } System.out.println(totalOfValuesDoubled);

Functional:

System.out.println( numbers.stream() .mapToInt(number -> number * 2) .sum()); // Also this works : reduce(0, (c , e) -> c+e));

Page 30: Functional Programming In Jdk8

Reduce On Streamsreduce() : Transforms the collection into a single value or non-stream itself- A reduce applies a function which takes two input and give one output i.e. Binary

Function. E.g. reduce(0, (c , e) -> c+e)- Reduce starts from 0 , takes carry over and element as another input and then does

the sum of carry over and element. Note carry over is from map.- Reduce on Stream<T> takes two parameters:- First parameter is of type T- Second parameter is of type BiFunction<R, T, R> to produce a result of type R- Where T is the element and R is both the input and output type because input at one

stage which in turn becomes output- Specialized Reduce Functions:• Sum()• Collect()

toList() toMap() toSet()

Page 31: Functional Programming In Jdk8

Filter The Streamsfilter(): a room of wonderful people standup if your age>80 ; age>40 && age <60- 0 <= Number of elements in the Output <= Number of elements in the Input- Input: if you have a Stream<T> then filter takes a Predicate<T>- Takes Predicate as an argument which has test method and returns boolean- Both map & filter stay within their swim lanes, take an element and performs some

kind of operation on it but not looking for elements on the left & right e.g. if I come & ask you your name

- Reduce cut across the swim lanes- Takes the first element coming in, performs the operation, push the result out that

results becomes the input; step forward

Page 32: Functional Programming In Jdk8

Collect The Streams collect(): - 0 <= Number of elements in the Output <= Number of elements in the Input- Input: if you have a Stream<T> then filter takes a Predicate<T>- Takes Predicate as an argument which has test method and returns boolean- Both map & filter stay within their swim lanes, take an element and performs some

kind of operation on it but not looking for elements on the left & right e.g. if I come & ask you your name

- Reduce cut across the swim lanes- Takes the first element coming in, performs the operation, push the result out that

results becomes the input; step forward

Page 33: Functional Programming In Jdk8

Efficiency Of StreamsList<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10); //double the first even number greater than 3 from the list int result = 0; for(int e : numbers) { if(e > 3 && e%2 == 0) { result = e * 2; break; } }System.out.println("Result="+ result); // How does this code looks to you?Spaghetti, Scares the Heck Out of Me

//Note : Imperative code has low level constructs ; hides truth ; waiting to hurt you

Page 34: Functional Programming In Jdk8

Streams to the Rescue !!List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10); //double the first even number greater than 3 from the list System.out.println( numbers.stream() .filter(e -> e >3) // given an element return element >3 ; test 10 elements .filter(e -> e%2==0) // test 7 elements .map(e -> e*2) // test 4 elements .findFirst() // test 1 element .orElse(0) ); //Answer is Optional[8] why Optional[8]? because the given input may not have a even number or number > 3 . In such case i want to display 0 using OrElse which substitutes Optional valueGreat !! What About Performance??//Lets Measure It: 22 vs 8 computations of Imperative – That’s Not the Truth

Page 35: Functional Programming In Jdk8

Truth is Lazy Evaluation Time for Life Lesson: Feature of Streams is characteristically shared by both of my daughters who are Lazy to the book & are doing something in their bedroom having fun fighting with each other and I ask :

Have you done your Homework? - Yes Daddy How did it go? - Fantastic Daddy Are there any concerns? - No we are good Can i see the results please? - And then i dont see them for a long time

So I ask my wife where are the children? Have you asked for the Homework? - My wife says to the Children Daddy is Coming and it triggers Oh dear I got to get some work done here

Page 36: Functional Programming In Jdk8

Streams Are Lazy Too !!• Methods like filter & map are called intermediate functions; they are lazy and dont do much

work whereas findFirst are called terminal functions which trigger the computations

• All intermediate functions get fused into one ball of functions in a pipeline and gets executed only when a terminal function is called.

To prove : comment out findFirst() then print SOP("here") in the next line And guess what it never did the work i.e. intermediate functions never get executed. Its just like a day in office when boss is not around; no work gets done i.e. postpone evaluation and no computation cycles

Page 37: Functional Programming In Jdk8

Demo Time : Lazy Evaluationpublic static boolean isGreaterThan3(int number) { return number > 3; } public static boolean isEven(int number) { return number % 2 == 0; } public static int doubleIt(int number) { return number * 2; } public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); //double the first even number greater than 3 from the list System.out.println( numbers.stream() .filter(Sample::isGreaterThan3) .filter(Sample::isEven) .mapToInt(Sample::doubleIt) .findFirst() .getAsInt() ); }

Page 38: Functional Programming In Jdk8

Don’t’s With Lambda Rulesx Don’t put Multiples Lines Of Code in Lambdax No large lambda expressionsx Avoid Noisex Duplication Is Evil. One Lambda has same code as other

lambdax Logic In Lambda results in Hard to Test. So write the logic

in functions

Page 39: Functional Programming In Jdk8

Method Reference Simple Pass Thru Receive An Argument don’t alter it but simply pass thru Most ultimate glue code Parameter as an Argument: System.out is an Object on which the

println method is called hence System.out::println Parameter as an Argument using Static Method: String::valueOf

Please note valueOf() is a static method on String object whereas println is an instance method on System.out object

Parameter As A Target: String::toString

Page 40: Functional Programming In Jdk8

Reactive Programming In RP: FP++ And parallel streams ability to lazy evaluation ability to communicate a higher level of abstraction

Use case: You call a Web Service which returns a error in place of data and you have to handle the exception in one of your threads

Page 41: Functional Programming In Jdk8

Parallelism

Page 42: Functional Programming In Jdk8

Parallel StreamsJava 8 introduces parallel streamsFork/Join framework abstractionStream partitioned into substreamsAggregation is applied in parallel to substreamsAccess parallel streams via

Collections.parallelStream()BaseStream.parallel()

Page 43: Functional Programming In Jdk8

Parallel ExecutionIntStream.range(0,20) .parallel() .filter( x -> (x % 2) == 0) .forEach(System.out::println);

Ordouble avgDays = months .parallelStream() .mapToInt(m -> m.days) .average().getAsDouble();

Page 44: Functional Programming In Jdk8

Other Language ChangesDefault Methodsjava.util.Optional<T> classAnnotations on Types

Page 45: Functional Programming In Jdk8

Conclusion Two Key Features : invokedynamic & laziness of streams

functions are pure and lets all adapt to functional hygiene and write better quality code. Take a step in right direction, create a Haha moment for yourself when your code reads like a story / problem statement