Top Banner
Functional Thinking: Introduction to Lambdas Ganesh Samarthyam [email protected] www.designsmells.com
85

Functional Thinking - Programming with Lambdas in Java 8

Apr 16, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Functional Thinking - Programming with Lambdas in Java 8

Functional Thinking: Introduction to Lambdas

Ganesh [email protected]

www.designsmells.com

Page 2: Functional Thinking - Programming with Lambdas in Java 8

Adapt: Learn functional programming

Page 3: Functional Thinking - Programming with Lambdas in Java 8
Page 4: Functional Thinking - Programming with Lambdas in Java 8

Programming paradigms

Langauge Paradigm

Declarative Languages

Imperative Languages

Logic Languages

Functional Languages

Procedural Languages

Object-Oriented Languages

e.g. Prolog e.g. Haskell e.g. C e.g. Java

Page 5: Functional Thinking - Programming with Lambdas in Java 8
Page 6: Functional Thinking - Programming with Lambdas in Java 8
Page 7: Functional Thinking - Programming with Lambdas in Java 8
Page 8: Functional Thinking - Programming with Lambdas in Java 8
Page 9: Functional Thinking - Programming with Lambdas in Java 8
Page 10: Functional Thinking - Programming with Lambdas in Java 8

Perspective - for loops!List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {

System.out.println(string);}

External Iteration

Page 11: Functional Thinking - Programming with Lambdas in Java 8

Perspective - for loops!

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");strings.forEach(string -> System.out.println(string));

Internal Iteration

Page 12: Functional Thinking - Programming with Lambdas in Java 8

Perspective - for loops!

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");strings.forEach(string -> System.out.println(string));

Internal Iteration

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {

System.out.println(string);}

External Iteration

Page 13: Functional Thinking - Programming with Lambdas in Java 8

Perspective - for loops!

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");strings.forEach(string -> System.out.println(string));

Internal Iteration

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {

System.out.println(string);}

External Iteration

Procedural thinking

Functional thinking

Page 14: Functional Thinking - Programming with Lambdas in Java 8

Lambdas

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);

Lambda functions!

Page 15: Functional Thinking - Programming with Lambdas in Java 8

Lambdas

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);

Capture in a variable

Execute later

Page 16: Functional Thinking - Programming with Lambdas in Java 8

What are lambda functions?

❖ (Java 8) One way to think about lambdas is “anonymous function” or “unnamed function” - they are functions without a name and are not associated with any class

❖ They don’t change external state

Page 17: Functional Thinking - Programming with Lambdas in Java 8

What is functional programming?

❖ Functional languages view programs as an entity—called a function—that accepts inputs and produces output

❖ Functions are connected together by their outputs to other functions’ inputs

❖ Underlying approach: “Evaluate an expression. Then use the results for something else.”

Page 18: Functional Thinking - Programming with Lambdas in Java 8

Functional languages

Haskell

Common Lisp

SchemeClojure

F#

OCaml

Erlang Hope

ScalaR

Page 19: Functional Thinking - Programming with Lambdas in Java 8

Languages that support functional programming

C# (3.0)

Python

JavaScriptD

Fortran 95

Visual Basic

PHP Java (8)

C++11

Page 20: Functional Thinking - Programming with Lambdas in Java 8

Lambdas added in Java 8

Page 21: Functional Thinking - Programming with Lambdas in Java 8

“Success is very largely a matter of adjusting one's self to the ever-varying and changing environments of life”

- Napoleon Hill

Page 22: Functional Thinking - Programming with Lambdas in Java 8

Popular Languages

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

Page 23: Functional Thinking - Programming with Lambdas in Java 8

Popular Languages

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

Page 24: Functional Thinking - Programming with Lambdas in Java 8

Productive programming with lambdasimportjava.io.*;

classType{ publicsta7cvoidmain(String[]files){ //processeachfilepassedasargument for(Stringfile:files){ //tryopeningthefilewithFileReader try(FileReaderinputFile=newFileReader(file)){ intch=0; while((ch=inputFile.read())!=-1){ //chisoftypeint-convertitbacktochar System.out.print((char)ch); } }catch(FileNotFoundExcep7onfnfe){ System.err.prinR("Cannotopenthegivenfile%s",file); } catch(IOExcep7onioe){ System.err.prinR("Errorwhenprocessingfile%s;skippingit",file); } //try-with-resourceswillautoma7callyreleaseFileReaderobject } }}

args.each{printlnnewFile(it).getText()}

Page 25: Functional Thinking - Programming with Lambdas in Java 8

Workshop overview

❖ Assumes that you already know Java

❖ You’ll know how to use Java 8 lambdas and streams after this session

❖ Try out the programs in your machine

Page 26: Functional Thinking - Programming with Lambdas in Java 8

Lambdas in Java 8

Page 27: Functional Thinking - Programming with Lambdas in Java 8

Code examples & images from my upcoming book: Oracle Certified Professional Java SE 8 Programmer Exam

1Z0-809 by S G Ganesh, Hari Kiran Kumar and Tushar Sharma, Apress, December 2015

Page 28: Functional Thinking - Programming with Lambdas in Java 8

Java 8 lambdas - “Hello world!”

interface LambdaFunction { void call(); }

class FirstLambda { public static void main(String []args) { LambdaFunction lambdaFunction = () -> System.out.println("Hello world"); lambdaFunction.call(); } }

Page 29: Functional Thinking - Programming with Lambdas in Java 8

Java 8 lambdas - “Hello world!”

interface LambdaFunction { void call(); }

class FirstLambda { public static void main(String []args) { LambdaFunction lambdaFunction = () -> System.out.println("Hello world"); lambdaFunction.call(); } }

Functional interface - provides signature for lambda functions

Lambda function/expression

Call to the lambda

Prints “Hello world” on the console when executed

Page 30: Functional Thinking - Programming with Lambdas in Java 8

Parts of a lambda expression

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

No parameters, i.e., ()

Arrow operator that separates parameters and the body The lambda body

Return type “void” inferred from the body

Page 31: Functional Thinking - Programming with Lambdas in Java 8

Functional interfaces

@FunctionalInterface interface LambdaFunction { void call(); }

Functional interface

Abstract method providing the signature of the lambda function

Annotation to explicitly state that it is a functional interface

Page 32: Functional Thinking - Programming with Lambdas in Java 8

Using built-in functional interfaces// within Iterable interface default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t);

} }

// in java.util.function package @FunctionalInterface public interface Consumer<T> {

void accept(T t); // the default andThen method elided

}

Page 33: Functional Thinking - Programming with Lambdas in Java 8

Using built-in functional interfaces

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); strings.forEach(string -> System.out.println(string));

Page 34: Functional Thinking - Programming with Lambdas in Java 8

Method references

Method references - “syntactic sugar” for lambda functions

They “route” function parameters

arg -> System.out.println(arg)

System.out::println

Page 35: Functional Thinking - Programming with Lambdas in Java 8

Method references

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = System.out::println; strings.forEach(printString);

Method reference

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);

Page 36: Functional Thinking - Programming with Lambdas in Java 8

Method references

Cannot use method references when lambda functions do more than“routing” function parameters

strings.forEach(string -> System.out.println(string.toUpperCase()));

More processing here than just “routing” parameters

Page 37: Functional Thinking - Programming with Lambdas in Java 8

Method references List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = System.out::println; strings.forEach(printString);

public static void printUpperCaseString(String string) { System.out.println(string.toUpperCase()); }

strings.forEach(MethodReference::printUpperCaseString);

Page 38: Functional Thinking - Programming with Lambdas in Java 8

“Effectively final” variables

import java.util.Arrays; import java.util.List;

class PigLatin { public static void main(String []args) { String suffix = "ay"; List<String> strings = Arrays.asList("one", "two", "three", "four"); strings.forEach(string -> System.out.println(string + suffix)); } } Accessing “local variable” suffix

here; hence it is considered “effectively final”

Page 39: Functional Thinking - Programming with Lambdas in Java 8

“Effectively final” variablesimport java.util.Arrays; import java.util.List;

class PigLatin { public static void main(String []args) { String suffix = "ay"; List<String> strings = Arrays.asList("one", "two", "three", “four");

suffix = "e"; // assign to suffix variable strings.forEach(string -> System.out.println(string + suffix)); } }

PigLatinAssign.java:9: error: local variables referenced from a lambda expression must be final or effectively final strings.forEach(string -> System.out.println(string + suffix)); ^ 1 error

Page 40: Functional Thinking - Programming with Lambdas in Java 8

One-liner #1

Files.lines(Paths.get("FileRead.java")).forEach(System.out::println);

This code prints the contents of the file “FileRead.java” in the

current directory

Page 41: Functional Thinking - Programming with Lambdas in Java 8

One-liner #2

Pattern.compile(" ").splitAsStream("java 8 streams").forEach(System.out::println);

This code splits the input string “java 8 streams” based on whitespace and hence

prints the strings “java”, “8”, and “streams” on the console

Page 42: Functional Thinking - Programming with Lambdas in Java 8

One-liner #3

new Random().ints().limit(5).forEach(System.out::println);

Generates 5 random integers and prints them on the console

Page 43: Functional Thinking - Programming with Lambdas in Java 8

One-liner #4

"hello".chars().sorted().forEach(ch -> System.out.printf("%c ", ch));

Extracts characters in the string “hello”, sorts the chars and prints the chars

Page 44: Functional Thinking - Programming with Lambdas in Java 8

Stream API

Page 45: Functional Thinking - Programming with Lambdas in Java 8

First stream example

"hello".chars().sorted().forEach(ch -> System.out.printf("%c ", ch));

The chars() method in String results in a Stream; sorted() sorts

the entries in the stream

// prints e h l l o

Page 46: Functional Thinking - Programming with Lambdas in Java 8

Stream pipeline

Streamsource

Intermediateopera1ons

Terminalopera1on

stream

stream

Examples:IntStream.range(),Arrays.stream()

Examples:map(),filter(),dis1nct(),sorted()

Examples:sum(),collect(),forEach(),reduce()

Page 47: Functional Thinking - Programming with Lambdas in Java 8

Stream pipeline example

Arrays.stream(Object.class.getMethods()) // source .map(method -> method.getName()) // intermediate op .distinct() // intermediate op .forEach(System.out::println); // terminal operation

Page 48: Functional Thinking - Programming with Lambdas in Java 8

Stream pipeline example

Method[] objectMethods = Object.class.getMethods(); Stream<Method> objectMethodStream = Arrays.stream(objectMethods); Stream<String> objectMethodNames = objectMethodStream.map(method -> method.getName()); Stream<String> uniqueObjectMethodNames = objectMethodNames.distinct(); uniqueObjectMethodNames.forEach(System.out::println);

Page 49: Functional Thinking - Programming with Lambdas in Java 8

Stream pipeline illustration

DoubleStream.of(1.0,4.0,9.0) map(Math::sqrt) .peek(System.out::

println)

StreamSource(withelements1.0,4.0,and9.0)

IntermediateOpera=on1(mapsto

elementvalues1.0,2.0,and3.0)

IntermediateOpera=on2

(prints1.0,2.0,and3.0)

.sum();

TerminalOpera=on(returnsthesum6.0)

DoubleStream.of(1.0, 4.0, 9.0) .map(Math::sqrt) .peek(System.out::println) .sum();

Page 50: Functional Thinking - Programming with Lambdas in Java 8

Stream sources

IntStream.range(1, 6)

You can use range or iterate factory methods in the

IntStream interface

IntStream.iterate(1, i -> i + 1).limit(5)

Page 51: Functional Thinking - Programming with Lambdas in Java 8

Stream sources

Arrays.stream(new int[] {1, 2, 3, 4, 5}) Arrays.stream(new Integer[] {1, 2, 3, 4, 5})

You can use the stream() method in java.util.Arrays class to create a

stream from a given array

Page 52: Functional Thinking - Programming with Lambdas in Java 8

Stream sources

Stream.of(1, 2, 3, 4, 5) Stream.of(new Integer[]{1, 2, 3, 4, 5})

We can also create streams using factories and builders (e..g, of() and build() methods

in the Stream interface)

Stream.builder().add(1).add(2).add(3).add(4).add(5).build()

Page 53: Functional Thinking - Programming with Lambdas in Java 8

Stream sources

• The lines() method in java.nio.file.Files class • The splitAsStream() method in java.util.regex.Pattern class • The ints() method in java.util.Random class • The chars() method in java.lang.String class

There are numerous classes/interfaces in the Java library that return a stream

Page 54: Functional Thinking - Programming with Lambdas in Java 8

Intermediate operations

Stream<T> filter(Predicate<? super T> check) Removes the elements for which the check predicate returns false.

<R> Stream<R> map(Function<? super T,? extends R> transform)

Applies the transform() function for each of the elements in the stream.

Stream<T> distinct() Removes duplicate elements in the stream; it uses the equals() method to determine if an element is repeated in the stream.

Stream<T> sorted() Stream<T> sorted(Comparator<? super T> compare)

Sorts the elements in its natural order. The overloaded version takes a Comparator – you can pass a lambda function for that.

Stream<T> peek(Consumer<? super T> consume)

Returns the same elements in the stream, but also executes the passed consume lambda expression on the elements.

Stream<T> limit(long size) Removes the elements if there are more elements than the given size in the stream.

Page 55: Functional Thinking - Programming with Lambdas in Java 8

Terminal operations

void forEach(Consumer<? super T> action)

Calls the action for every element in the stream.

Object[] toArray() Returns an Object array that has the elements in the stream.

Optional<T> min(Comparator<? super T> compare)

Returns the minimum value in the stream (compares the objects using the given compare function).

Optional<T> max(Comparator<? super T> compare)

Returns the maximum value in the stream (compares the objects using the given compare function).

long count() Returns the number of elements in the stream.

Page 56: Functional Thinking - Programming with Lambdas in Java 8

Using “range” instead of “for” loop

IntStream.range(1, 10).map(i -> i * i).forEach(System.out::println);

Using streams instead of imperative for i = 1 to 1, print i * i

Prints: 1 4 9 16 25 36 49 64 81

Page 57: Functional Thinking - Programming with Lambdas in Java 8

“Mapping” elements in a stream

1 2 3 4 5

1 4 9 16 25

map(i->i*i)

Page 58: Functional Thinking - Programming with Lambdas in Java 8

Streams can be “infinite”

Page 59: Functional Thinking - Programming with Lambdas in Java 8

“Generating” even numbers

IntStream.iterate(0, i -> i + 2).forEach(System.out::println);

The problem is it creates infinite number of even numbers!

Page 60: Functional Thinking - Programming with Lambdas in Java 8

“Generating” limited even numbers

IntStream .iterate(0, i -> i + 2) .limit(5) .forEach(System.out::println);

Using the “limit” function to limit the stream to 5 integers

Page 61: Functional Thinking - Programming with Lambdas in Java 8

“Generating” limited even numbers

IntStream .iterate(0, i -> i + 1) .filter(i -> (i % 2) == 0) .limit(5) .forEach(System.out::println);

You can also use the “filter” method

Page 62: Functional Thinking - Programming with Lambdas in Java 8

“Reduction” using “sum” function

System.out.println(IntStream.rangeClosed(0, 10).sum());

Sum of integers from 1 to 10 using “implicit reduction”

Page 63: Functional Thinking - Programming with Lambdas in Java 8

“Reduction” using “sum” function

System.out.println( IntStream .rangeClosed(1, 5) .reduce((x, y) -> (x * y)) .getAsInt());

Factorial of 5 using “explicit reduce”

Page 64: Functional Thinking - Programming with Lambdas in Java 8

Using “map” function

List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); strings.stream().map(value -> value.toUpperCase()).forEach(System.out::println);

public static void printUpperCaseString(String string) { System.out.println(string.toUpperCase()); }

strings.forEach(MethodReference::printUpperCaseString);

Page 65: Functional Thinking - Programming with Lambdas in Java 8

Using “collect” function

String boxedString = Arrays .asList("eeny", "meeny", "miny", "mo") .stream() .collect(Collectors.joining(“ ,", "[", "]")); System.out.println(boxedString);

Prints: [eeny, meeny, miny, mo]

Page 66: Functional Thinking - Programming with Lambdas in Java 8

Using Files.list()

Files.list(Paths.get(".")) .map(path -> path.toAbsolutePath()) .forEach(System.out::println);

Page 67: Functional Thinking - Programming with Lambdas in Java 8

Built-in interfacesPredicate<T> Checks a condition and returns a

boolean value as resultIn filter() method in java.util.stream.Stream which is used to remove elements in the stream that don’t match the given condition (i.e., predicate) as Consumer<T> Operation that takes an argument but

returns nothingIn forEach() method in collections and in java.util.stream.Stream; this method is used for traversing all the elements in the collection or Function<T,

R>Functions that take an argument and return a result

In map() method in java.util.stream.Stream to transform or operate on the passed value and return a result.

Supplier<T> Operation that returns a value to the caller (the returned value could be same or different values)

In generate() method in java.util.stream.Stream to create a infinite stream of elements.

Page 68: Functional Thinking - Programming with Lambdas in Java 8

Built-in interfaces

Page 69: Functional Thinking - Programming with Lambdas in Java 8

Streams are “lazy”

Page 70: Functional Thinking - Programming with Lambdas in Java 8

Cannot “reuse” a stream!

Page 71: Functional Thinking - Programming with Lambdas in Java 8

Important stream interfaces

<<interface>>java.u0l.stream.BaseStream

<<interface>>java.u0l.stream.IntStream

<<interface>>java.u0l.stream.LongStream

<<interface>>java.u0l.stream.DoubleStream

<<interface>>java.u0l.stream.Stream<T>

Page 72: Functional Thinking - Programming with Lambdas in Java 8

map vs. flatMap methods

1 2 3 4 5

1 4 9 16 25

map(i->i*i)

1 3 5

1 3 5 2 4

flatMap(ints->ints.stream())

2 4

sorted()

1 2 3 4 5

1 4 9 16 25

map(i->i*i)

Page 73: Functional Thinking - Programming with Lambdas in Java 8

String limerick = "There was a young lady named Bright " + "who traveled much faster than light " + "She set out one day " + "in a relative way " + "and came back the previous night ";

IntSummaryStatistics wordStatistics = Pattern.compile(" ") .splitAsStream(limerick) .mapToInt(word -> word.length()) .summaryStatistics();

System.out.printf(" Number of words = %d \n Sum of the length of the words = %d \n" + " Minimum word size = %d \n Maximum word size %d \n " +

" Average word size = %f \n", wordStatistics.getCount(), wordStatistics.getSum(), wordStatistics.getMin(), wordStatistics.getMax(), wordStatistics.getAverage());

Data calculation methods in stream

Page 74: Functional Thinking - Programming with Lambdas in Java 8

Parallel streams

Page 75: Functional Thinking - Programming with Lambdas in Java 8

Threading problems

Page 76: Functional Thinking - Programming with Lambdas in Java 8

Threading problems

Page 77: Functional Thinking - Programming with Lambdas in Java 8

Fork-join frameworkforkJoinAlgorithm() { fork (split) the tasks; join the tasks; compose the results; }

doRecursiveTask(input) { if (the task is small enough to be handled by a thread) { compute the small task; if there is a result to return, do so } else { divide (i.e., fork) the task into two parts call compute() on first task, join() on second task, return combined results } }

Page 78: Functional Thinking - Programming with Lambdas in Java 8

Fork-join framework

Page 79: Functional Thinking - Programming with Lambdas in Java 8

Stream - for primesimport java.util.stream.LongStream;

class PrimeNumbers { private static boolean isPrime(long val) { for(long i = 2; i <= val/2; i++) { if((val % i) == 0) { return false; } } return true; } public static void main(String []args) { long numOfPrimes = LongStream.rangeClosed(2, 100_000) .filter(PrimeNumbers::isPrime) .count(); System.out.println(numOfPrimes); } }

Page 80: Functional Thinking - Programming with Lambdas in Java 8

Stream - for primesimport java.util.stream.LongStream;

class PrimeNumbers { private static boolean isPrime(long val) { for(long i = 2; i <= val/2; i++) { if((val % i) == 0) { return false; } } return true; } public static void main(String []args) { long numOfPrimes = LongStream.rangeClosed(2, 100_000)

.parallel() .filter(PrimeNumbers::isPrime) .count(); System.out.println(numOfPrimes); } }

Page 81: Functional Thinking - Programming with Lambdas in Java 8

Be careful with parallel streamsimport java.util.Arrays;

class StringConcatenator { public static String result = ""; public static void concatStr(String str) { result = result + " " + str; } }

class StringSplitAndConcatenate { public static void main(String []args) { String words[] = "the quick brown fox jumps over the lazy dog".split(" "); Arrays.stream(words).forEach(StringConcatenator::concatStr); System.out.println(StringConcatenator.result); } }

Page 82: Functional Thinking - Programming with Lambdas in Java 8
Page 83: Functional Thinking - Programming with Lambdas in Java 8

Adapt: Learn functional programming

Page 84: Functional Thinking - Programming with Lambdas in Java 8

Image credits❖ http://mayhemandmuse.com/wp-content/uploads/2013/04/This-optical-illusion-drawing-by-WE-

Hill-shows-both-his-wife-and-his-mother-in-law.jpg

❖ http://www.webtrafficroi.com/wp-content/uploads/2012/10/mahatma-gandhi-apple-think-different.jpg

❖ http://rexx-language-association-forum.44760.x6.nabble.com/file/n2236/Ruby-lambda-function.jpg

❖ http://www.ibm.com/developerworks/library/j-jn16/figure1.png

❖ http://www.ibm.com/developerworks/library/j-jn16/figure2.png

❖ http://img.viralpatel.net/2014/01/java-lambda-expression.png

❖ http://www.codercaste.com/wp-content/uploads/2011/01/animals.png

❖ http://blog.takipi.com/wp-content/uploads/2014/03/blog_lambada_2.png

❖ http://quotespictures.com/wp-content/uploads/2014/01/it-is-not-the-strongest-of-the-species-that-survive-nor-the-most-intelligent-but-the-one-most-responsive-to-change-charles-darwin.jpg

❖ http://7-themes.com/data_images/out/27/6859733-surfing-wallpaper.jpg