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

Functional Thinking - Programming with Lambdas in Java 8

Embed Size (px)

Citation preview

Functional Thinking: Introduction to Lambdas

Ganesh [email protected]

www.designsmells.com

Adapt: Learn functional programming

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

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

System.out.println(string);}

External Iteration

Perspective - for loops!

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

Internal Iteration

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

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

Lambdas

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

Lambda functions!

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

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

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.”

Functional languages

Haskell

Common Lisp

SchemeClojure

F#

OCaml

Erlang Hope

ScalaR

Languages that support functional programming

C# (3.0)

Python

JavaScriptD

Fortran 95

Visual Basic

PHP Java (8)

C++11

Lambdas added 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

Popular Languages

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

Popular Languages

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

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()}

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

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

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(); } }

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

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

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

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

}

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));

Method references

Method references - “syntactic sugar” for lambda functions

They “route” function parameters

arg -> System.out.println(arg)

System.out::println

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);

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

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);

“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”

“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

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

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

One-liner #3

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

Generates 5 random integers and prints them on the console

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

Stream API

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

Stream pipeline

Streamsource

Intermediateopera1ons

Terminalopera1on

stream

stream

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

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

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

Stream pipeline example

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

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);

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();

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)

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

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()

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

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.

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.

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

“Mapping” elements in a stream

1 2 3 4 5

1 4 9 16 25

map(i->i*i)

Streams can be “infinite”

“Generating” even numbers

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

The problem is it creates infinite number of even numbers!

“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

“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

“Reduction” using “sum” function

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

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

“Reduction” using “sum” function

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

Factorial of 5 using “explicit reduce”

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);

Using “collect” function

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

Prints: [eeny, meeny, miny, mo]

Using Files.list()

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

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.

Built-in interfaces

Streams are “lazy”

Cannot “reuse” a stream!

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>

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)

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

Parallel streams

Threading problems

Threading problems

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 } }

Fork-join framework

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); } }

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); } }

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); } }

Adapt: Learn functional programming

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