Is java8 a true functional programming language

Preview:

Citation preview

IS JAVA 8 A TRUE FUNCTIONAL PROGRAMMING LANGUAGE ?

- Samir Chekkal

- Saad El Khlifi

1. Programming Paradigm Overview

2. Imperative Pardigm Vs Functional Paradigm

3. Corner Stones of Functional Paradigm

1. Immutablity

2. Recursion

3. Functions as first class citizens

4. Higher order functions

5. Lazyness

4. Conclusion

Plan

- A programming paradigm is a general approach, orientation, or philosophy

of programming that can be used when implementing a program.

- Main programming paradigms:

- Imperative programming: C, Java, Scala ...

- Functionnal programming: Haskell, ML, Scala, Java 8 (?) ...

- Logic programming: Prolog ...

- Object Oriented Programming: Java, Scala, ...

1.Programming Paradigm Overview

static List<String> approvisionnement() {

List<String> refs = new ArrayList<>();

int index = 0;

for(Product p : Store.catalog()) {

if(p.getCategory() == Product.Category.MOBILE_PHONE) {

refs.add(p.getRef());

index ++;

if(index > 10)

break;

}

}

Collections.sort(refs);

return refs;

}

2.Imperative Pardigm Vs Functional Paradigm

static Map<Product.Category, List<Product>> categories() {

Map<Product.Category, List<Product>> result = new HashMap<>();

for(Product p : Store.catalog()) {

if(result.get(p.getCategory()) != null) {

result.get(p.getCategory()).add(p);

} else {

List<String> catProducts = new ArrayList<>();

catProducts.add(p);

result.put(p.getCategory(), catProducts);

}

}

return result;

}

2.Imperative Pardigm Vs Functional Paradigm

static List<String> approvisionnement() {

return Store.catalog()

.stream()

.filter(p -> p.getCategory() == Product.Category.MOBILE_PHONE)

.limit(10)

.map(Product::getRef)

.sorted()

.collect(toList());

}

2.Imperative Pardigm Vs Functional Paradigm

static Map<Product.Category, List<Product>> categories() {

return Store.catalog()

.stream()

.collect(groupingBy(Product::getCategory));

}

static Map<Product.Category, List<String>> categories() {

return Store.catalog()

.stream()

.collect(groupingBy(Product::getCategory,

mapping(Product::getRef, toList())));

}

2.Imperative Pardigm Vs Functional Paradigm

3. Corner Stones of Functional Paradigm

1. Immutablity

2. Recursion

3. Functions as first class citizens

4. Higher order functions

5. Lazyness

- High level coding

- Mutability + Shared state = Time

bomb

- Parallelism

- But Threads API is complexe

- For free with streams! Really ?

3.1 Immutablity

static long badIdea() {

// Tables are not thread safe:

// Correctness ?

long[] acc = {0L};

LongStream

.rangeClosed(1, LIMIT)

.parallel()

.forEach( i -> acc[0] += i);

return acc[0];

}

static long lessBadIdea() {

// Thread safe , correct response

// Performance ?

AtomicLong acc = new AtomicLong(0L);

LongStream

.rangeClosed(1, LIMIT)

.parallel()

.forEach( i -> acc.addAndGet(i));

return acc.get();

}

static long sumByReduction() {

return LongStream

.rangeClosed(1, LIMIT)

.parallel()

.sum();

}

3.1 Immutablity

Result: 5000000050000000

in ~288 msResult: 5000000050000000

in ~8306 ms

Result: 1839299186097435

in ~342 ms

static long factorialImperative(final int n) {

long r = 1;

for (int i = 1; i <= n; i++) {

r *= i;

}

return r;

}

static long recFact(final long n) {

return (n == 1) ? 1 : n*recFact(n-1);

}

3.2.Recursion

recFact(5) = 5*recFact(4)

= 5*(4*recFact(3))

= 5*(4*(3*recFact(2)))

= 5*(4*(3*(2*recFact(1)))

= 5*(4*(3*(2*1)))

= 5*(4*(3*2))

= 5*(4*6)

= 5*24

= 120

3.2.Recursion

static long factorialTailRecursive(final long n) {

return factorialHelper(n, 1);

}

private static long factorialHelper(final long n, final long acc) {

return n == 1 ? acc : factorialHelper(n-1, n*acc);

}

3.2.Recursion

FactorialTailRecursive(5) = factorialHelper(5, 1)

= factorialHelper(4, 5)

= factorialHelper(3, 20)

= factorialHelper(2, 60)

= factorialHelper(1, 120)

= 120

3.2.Recursion

Thread t = new Thread(new Runnable() {

public void run(){

System.out.println("Hello world");

}

});

Button button = new Button("Send");

button.setOnAction(new EventHandler<ActionEvent>() {

public void handle(ActionEvent event) {

System.out.println("Button Pressed");

}

});

3.3.First class functions

Thread t = new Thread(new Runnable() {

public void run() -> {

System.out.println("Hello world");

}

});

Button button = new Button("Send");

button.setOnAction(new EventHandler<ActionEvent>() {

public void handle(ActionEvent event) -> {

System.out.println("Button Pressed");

}

});

3.3.First class functions

Thread t = new Thread( () -> System.out.println("Hello world") );

button.setOnAction( e -> System.out.println("Button Pressed"));

Lambda expression

(T0 arg0, … , Tn argn) -> Body //T0 … Tn are optional

3.3.First class functions

Method References

ContainingClass::staticMethodName // String::valueOf

containingObject::instanceMethodName //x::toString

ContainingType::methodName //String::toString

ClassName::new //String::new

3.3.First class functions

Is Lambda expression a true function literal ?

3.3.First class functions

java.util.function package to the rescue

• Predicate

• Consumer

• Supplier

• Function

• …

3.3.First class functions

static int sumOfInts(int a, int b) {

return a > b ? 0 : a + sumOfInts(a+1, b);

}

static int sumOfCubes(int a, int b) {

return a > b ? 0 : a*a*a + sumOfCubes(a+1, b);

}

static int sumOfFact(int a, int b) {

return a > b ? 0 : fact(a) + sumOfFact(a+1, b)

}

3.4.Higher order functions

static int higherSum(Function<Integer, Integer> f, int a, int b) {

return a > b ? 0 : f.apply(a) + higherSum(f, a + 1, b);

}

int sumOfSquare = higherSum(x->x*x, 1, 6);

int sumOfCube = higherSum(x->x*x*x, 5, 21);

int sumOfFactoriel = higherSum(x->fact(x), 13, 17);

…..

3.4.Higher order functions

static BiFunction<Integer, Integer, Integer> curriedSum(Function<Integer, Integer> f) {

return

(a, b) -> { return a > b ? 0 : f.apply(a) + curriedSum(f).apply(a+1, b); };

}

// Curryed version call

int sumOfSquare = curriedSum(x->x*x).apply(1, 6);

int sumOfCube = curriedSum(x->x*x*x).apply(5, 21);

int sumOfFactoriel = curriedSum(x->fact(x)).apply(13, 17);

…..

3.4.Higher order functions

List<String>

productsOfInterest(Predicate<Product> pred) {

return Store.products()

.stream()

.filter(pred)

.map(Product::getRef)

.limit(10)

.collect(toList());

}

filterlimit

distinct sotred

map

flatMap

3.5.Lazyness

List<String> productsOfInterest(Predicate<Product>

pred) {

return Store.products()

.stream()

.filter(pred)

.map(Product::getRef)

.limit(10)

.collect(toList());

}

collect

summax

forEachallMatch

anyMatch

oneMatch

count

reduce

3.5.Lazyness

IntStream is = IntStream.iterate(0, n -> n + 1);

int[] r1 = is.filter(n -> n%2 == 0).limit(5).toArray();

System.out.println(Arrays.toString(r1));

int[] r2 = is.filter(n -> n%3 == 0).map(x -> x*x).limit(7).toArray();

System.out.println(Arrays.toString(r2));

3.5.Lazyness

Q&A

References

- http://clojure.org/rationale Mutable stateful objects are the new spaghetti code

- Compositional Programming: http://www.cs.ox.ac.uk/research/pdt/ap/ssgp/slides/odersky.pdf

- http://www.info.ucl.ac.be/~pvr/paradigmsDIAGRAMeng108.pdf

- http://www.ibm.com/developerworks/aix/library/au-aix-multicore-multiprocessor/