productive programming in java 8 - with lambdas and streams

93
Productive Programming in Java 8 Covering Lambdas and Streams ocpjava.wordpress.com Ganesh Samarthyam ([email protected])

Upload: ganesh-samarthyam

Post on 15-Jan-2017

1.047 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Productive Programming in Java 8 - with Lambdas and Streams

Productive Programming

in Java 8

Covering Lambdas and Streams

ocpjava.wordpress.com

Ganesh Samarthyam ([email protected])

Page 2: Productive Programming in Java 8 - with Lambdas and Streams

❖ Programming examples are from our book: ❖ Oracle Certified

Professional Java SE 8 Programmer Exam 1Z0-809: A Comprehensive OCPJP 8 Certification Guide, S.G. Ganesh, Hari Kiran Kumar, Tushar Sharma, Apress, 2016.

❖ Website: ocpjava.wordpress.com

Page 3: Productive Programming in Java 8 - with Lambdas and Streams

Java

876…

I am evolving…

Page 4: Productive Programming in Java 8 - with Lambdas and Streams

Java 8: Latest (red-hot)

Page 5: Productive Programming in Java 8 - with Lambdas and Streams

Recent addition: lambdas

8

Page 6: Productive Programming in Java 8 - with Lambdas and Streams

Greek characters are scary!

Page 7: Productive Programming in Java 8 - with Lambdas and Streams

He he, but lambdas are fun, not scary

Page 8: Productive Programming in Java 8 - with Lambdas and Streams

Java meets functional programming (with lambdas)

Page 9: Productive Programming in Java 8 - with Lambdas and Streams

How different is lambdas?

if

while

for

switch

Page 10: Productive Programming in Java 8 - with Lambdas and Streams

Introducing our star feature - lambda

functions

Page 11: Productive Programming in Java 8 - with Lambdas and Streams

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

Lambda functions!

Page 12: Productive Programming in Java 8 - with Lambdas and Streams

But what are lambdas?

Page 13: Productive Programming in Java 8 - with Lambdas and Streams

Lambdas is just a fancy name for functions

without a name!

Page 14: Productive Programming in Java 8 - with Lambdas and Streams

What are lambdas?

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

❖ Functions don’t change external state

Page 15: Productive Programming in Java 8 - with Lambdas and Streams

Arrays.asList("eeny", "meeny", "miny", “mo”) .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

Lambda expression

Page 16: Productive Programming in Java 8 - with Lambdas and Streams

You can use lambdas for some amazing stuff

Page 17: Productive Programming in Java 8 - with Lambdas and Streams

sediment pre-carbon ultra-filter post-

carbonFiltered water

E.g., you can compose lambda functions as in pipes-and-filters

Page 18: Productive Programming in Java 8 - with Lambdas and Streams

$ cat limerick.txt There was a young lady of Niger Who smiled as she rode on a tiger. They returned from the ride With the lady inside And a smile on the face of the tiger.

Page 19: Productive Programming in Java 8 - with Lambdas and Streams

$ cat limerick.txt | tr -cs "[:alpha:]" "\n" | awk '{print length(), $0}' | sort | uniq1 a 2 as 2 of 2 on 3 And 3 Who 3 she 3 the 3 was 4 They 4 With 4 face 4 from 4 lady 4 ride 4 rode 5 Niger 5 There 5 smile 5 tiger 5 young 6 inside 6 smiled 8 returned

Page 20: Productive Programming in Java 8 - with Lambdas and Streams

List<String> lines = Files.readAllLines(Paths.get("./limerick.txt"), Charset.defaultCharset());

Map<Integer, List<String>> wordGroups = lines.stream() .map(line -> line.replaceAll("\\W", "\n").split("\n")) .flatMap(Arrays::stream) .sorted() .distinct() .collect(Collectors.groupingBy(String::length));

wordGroups.forEach( (count, words) -> { words.forEach(word -> System.out.printf("%d %s %n", count, word)); });

1 a 2 as 2 of 2 on 3 And 3 Who 3 she 3 the 3 was 4 They 4 With 4 face 4 from 4 lady 4 ride 4 rode 5 Niger 5 There 5 smile 5 tiger 5 young 6 inside 6 smiled 8 returned

Page 21: Productive Programming in Java 8 - with Lambdas and Streams

Lambdas & streams help in productive programming!

Page 22: Productive Programming in Java 8 - with Lambdas and Streams

public static void main(String []file) throws Exception { // process each file passed as argument

// try opening the file with FileReader try (FileReader inputFile = new FileReader(file[0])) { int ch = 0; while( (ch = inputFile.read()) != -1) { // ch is of type int - convert it back to char System.out.print( (char)ch ); } } // try-with-resources will automatically release FileReader object }

public static void main(String []file) throws Exception { Files.lines(Paths.get(file[0])).forEach(System.out::println); }

Existing APIs are enriched with lambdas and streams support

Page 23: Productive Programming in Java 8 - with Lambdas and Streams

So, lets get our hands dirty and start coding

Page 24: Productive Programming in Java 8 - with Lambdas and Streams

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 25: Productive Programming in Java 8 - with Lambdas and Streams

@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 26: Productive Programming in Java 8 - with Lambdas and Streams

Old functional interfaces

// in java.lang package interface Runnable { void run(); }

// in java.util package interface Comparator<T> { boolean compare(T x, T y); }

// java.awt.event package: interface ActionListener { void actionPerformed(ActionEvent e) }

// java.io package interface FileFilter { boolean accept(File pathName); }

Page 27: Productive Programming in Java 8 - with Lambdas and Streams

Default methods in interfaces

public interface Iterator<E> { boolean hasNext();

E next();

default void remove() { throw new UnsupportedOperationException("remove");

}

default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action);

while (hasNext()) action.accept(next());

} }

Page 28: Productive Programming in Java 8 - with Lambdas and Streams

Diamond inheritance problem

Page 29: Productive Programming in Java 8 - with Lambdas and Streams

Diamond inheritance problem?

interface Interface1 { default public void foo() { System.out.println("Interface1’s foo"); } }

interface Interface2 { default public void foo() { System.out.println("Interface2’s foo"); } }

public class Diamond implements Interface1, Interface2 { public static void main(String []args) { new Diamond().foo(); } }

Error:(9, 8) java: class Diamond inherits unrelated defaults for foo() from types Interface1 and Interface2

Page 30: Productive Programming in Java 8 - with Lambdas and Streams

Diamond inheritance problem?

interface Interface1 { default public void foo() { System.out.println("Interface1’s foo"); } }

interface Interface2 { default public void foo() { System.out.println("Interface2’s foo"); } }

public class Diamond implements Interface1, Interface2 { public void foo() { Interface1.super.foo(); }

public static void main(String []args) { new Diamond().foo(); } }

Add this definition to resolve the

ambiguity

Page 31: Productive Programming in Java 8 - with Lambdas and Streams

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 32: Productive Programming in Java 8 - with Lambdas and Streams

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 33: Productive Programming in Java 8 - with Lambdas and Streams

arg -> System.out.println(arg)

System.out::println

Method references - “syntactic sugar” for lambda functions

They “route” function parameters

Page 34: Productive Programming in Java 8 - with Lambdas and Streams

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 35: Productive Programming in Java 8 - with Lambdas and Streams

Using built-in functional interfaces

Page 36: Productive Programming in Java 8 - with Lambdas and Streams

Built-in functional interfaces are a part of the java.util.function

package (in Java 8)

Page 37: Productive Programming in Java 8 - with Lambdas and Streams

Using built-in functional 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 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 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 38: Productive Programming in Java 8 - with Lambdas and Streams

Predicate interface

Stream.of("hello", "world") .filter(str -> str.startsWith("h")) .forEach(System.out::println);

The filter() method takes a Predicate as an argument (predicates are

functions that check a condition and return a boolean value)

Page 39: Productive Programming in Java 8 - with Lambdas and Streams

Predicate interface

Page 40: Productive Programming in Java 8 - with Lambdas and Streams

Predicate interface

A Predicate<T> “affirms” something as true or false: it takes an argument of type T, and returns a

boolean value. You can call test() method on a Predicate object.

@FunctionalInterface public interface Predicate<T> {

boolean test(T t); // other methods elided

}

Page 41: Productive Programming in Java 8 - with Lambdas and Streams

Predicate interface: example

import java.util.function.Predicate;

public class PredicateTest { public static void main(String []args) {

Predicate<String> nullCheck = arg -> arg != null; Predicate<String> emptyCheck = arg -> arg.length() > 0; Predicate<String> nullAndEmptyCheck = nullCheck.and(emptyCheck); String helloStr = "hello"; System.out.println(nullAndEmptyCheck.test(helloStr)); String nullStr = null; System.out.println(nullAndEmptyCheck.test(nullStr));

} }

Prints: truefalse

Page 42: Productive Programming in Java 8 - with Lambdas and Streams

Predicate interface: example

import java.util.List; import java.util.ArrayList;

public class RemoveIfMethod { public static void main(String []args) {

List<String> greeting = new ArrayList<>(); greeting.add("hello"); greeting.add("world"); greeting.removeIf(str -> !str.startsWith("h")); greeting.forEach(System.out::println);

} }

Prints: hello

Page 43: Productive Programming in Java 8 - with Lambdas and Streams

Consumer interface

Stream.of("hello", "world") .forEach(System.out::println);

// void forEach(Consumer<? super T> action);

Prints: helloworld

Page 44: Productive Programming in Java 8 - with Lambdas and Streams

Consumer interface

Page 45: Productive Programming in Java 8 - with Lambdas and Streams

Consumer interface

A Consumer<T> “consumes” something: it takes an argument (of generic type T) and returns

nothing (void). You can call accept() method on a Consumer object.

@FunctionalInterface public interface Consumer<T> {

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

}

Page 46: Productive Programming in Java 8 - with Lambdas and Streams

Consumer interface: Example

Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());

printUpperCase.accept("hello");

Prints: HELLO

Page 47: Productive Programming in Java 8 - with Lambdas and Streams

Consumer interface: Example

import java.util.stream.Stream; import java.util.function.Consumer;

class ConsumerUse { public static void main(String []args) {

Stream<String> strings = Stream.of("hello", "world"); Consumer<String> printString = System.out::println; strings.forEach(printString);

} }

Prints: helloworld

Page 48: Productive Programming in Java 8 - with Lambdas and Streams

Function interface

import java.util.Arrays;

public class FunctionUse { public static void main(String []args) {

Arrays.stream("4, -9, 16".split(", ")) .map(Integer::parseInt) .map(i -> (i < 0) ? -i : i) .forEach(System.out::println);

} }

Prints: 4916

Page 49: Productive Programming in Java 8 - with Lambdas and Streams

Function interface

Page 50: Productive Programming in Java 8 - with Lambdas and Streams

Function interface

A Function<T, R> “operates” on something and returns something: it takes one argument (of

generic type T) and returns an object (of generic type R). You can call apply() method on a Function

object.

@FunctionalInterface public interface Function<T, R> {

R apply(T t); // other methods elided

}

Page 51: Productive Programming in Java 8 - with Lambdas and Streams

Function interface: example

Function<String, Integer> strLength = str -> str.length(); System.out.println(strLength.apply("supercalifragilisticexpialidocious"));

Prints: 34

Page 52: Productive Programming in Java 8 - with Lambdas and Streams

Function interface: example

import java.util.Arrays; import java.util.function.Function;

public class CombineFunctions { public static void main(String []args) {

Function<String, Integer> parseInt = Integer:: parseInt ; Function<Integer, Integer> absInt = Math:: abs ; Function<String, Integer> parseAndAbsInt = parseInt.andThen(absInt); Arrays.stream("4, -9, 16".split(", "))

.map(parseAndAbsInt)

.forEach(System. out ::println); }

}

Prints: 4916

Page 53: Productive Programming in Java 8 - with Lambdas and Streams

Supplier interface

import java.util.stream.Stream; import java.util.Random;

class GenerateBooleans { public static void main(String []args) {

Random random = new Random(); Stream.generate(random::nextBoolean)

.limit(2)

.forEach(System.out::println); }

}

Prints two boolean values “true” and “false”

in random order

Page 54: Productive Programming in Java 8 - with Lambdas and Streams

Supplier interface

Page 55: Productive Programming in Java 8 - with Lambdas and Streams

Supplier interface

A Supplier<T> “supplies” takes nothing but returns something: it has no arguments and

returns an object (of generic type T). You can call get() method on a Supplier object

@FunctionalInterface public interface Supplier<T> {

T get(); // no other methods in this interface

}

Page 56: Productive Programming in Java 8 - with Lambdas and Streams

Supplier interface: example

Supplier<String> currentDateTime = () -> LocalDateTime.now().toString(); System.out.println(currentDateTime.get());

Prints current time: 2015-10-16T12:40:55.164

Page 57: Productive Programming in Java 8 - with Lambdas and Streams

Summary of built-in interfaces in java.util.function interface

❖ There are only four core functional interfaces in this package: Predicate, Consumer, Function, and Supplier.

❖ The rest of the interfaces are primitive versions, binary versions, and derived interfaces such as UnaryOperator interface.

❖ These interfaces differ mainly on the signature of the abstract methods they declare.

❖ You need to choose the suitable functional interface based on the context and your need.

Page 58: Productive Programming in Java 8 - with Lambdas and Streams
Page 59: Productive Programming in Java 8 - with Lambdas and Streams

Java 8 streams (and parallel streams): Excellent example of applying functional

programming in practice

Page 60: Productive Programming in Java 8 - with Lambdas and Streams

But what are streams?

Page 61: Productive Programming in Java 8 - with Lambdas and Streams

Arrays.stream(Object.class.getMethods()) .map(method -> method.getName()) .distinct() .forEach(System.out::println);

wait equals toString hashCode getClass notify notifyAll

Page 62: Productive Programming in Java 8 - with Lambdas and Streams

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

Arrays.stream(Object.class.getMethods()) .map(method -> method.getName()) .distinct() .forEach(System.out::println);

Breaking up into separate (looong) statements for our

understanding

Page 63: Productive Programming in Java 8 - with Lambdas and Streams

stream pipelineStreamsource

Intermediateopera1ons

Terminalopera1on

stream

stream

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

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

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

Page 64: Productive Programming in Java 8 - with Lambdas and Streams

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 65: Productive Programming in Java 8 - with Lambdas and Streams

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 66: Productive Programming in Java 8 - with Lambdas and Streams

1 2 3 4 5

1 4 9 16 25

map(i->i*i)

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

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

Page 67: Productive Programming in Java 8 - with Lambdas and Streams

Stream.of (1, 2, 3, 4, 5) .map(i -> i * i) .peek(i -> System.out.printf("%d ", i)) .count();

prints: 1 4 9 16 25

Page 68: Productive Programming in Java 8 - with Lambdas and Streams

stream can be infinite

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

This code creates infinite stream of even numbers!

Page 69: Productive Programming in Java 8 - with Lambdas and Streams

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

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

Page 70: Productive Programming in Java 8 - with Lambdas and Streams

IntStream chars = "bookkeep".chars(); System.out.println(chars.count()); chars.distinct().sorted().forEach(ch -> System.out.printf("%c ", ch));

Cannot “reuse” a stream; this code throws IllegalStateException

Page 71: Productive Programming in Java 8 - with Lambdas and Streams

Streams are lazy!

Page 72: Productive Programming in Java 8 - with Lambdas and Streams

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 73: Productive Programming in Java 8 - with Lambdas and Streams

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 74: Productive Programming in Java 8 - with Lambdas and Streams

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

Generates 5 random integers and prints them on the console

Page 75: Productive Programming in Java 8 - with Lambdas and Streams

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

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

Page 76: Productive Programming in Java 8 - with Lambdas and Streams

Parallel Streams

Page 77: Productive Programming in Java 8 - with Lambdas and Streams

race conditions

Page 78: Productive Programming in Java 8 - with Lambdas and Streams
Page 79: Productive Programming in Java 8 - with Lambdas and Streams

deadlocks

Page 80: Productive Programming in Java 8 - with Lambdas and Streams
Page 81: Productive Programming in Java 8 - with Lambdas and Streams

I really really hate concurrency problems

Page 82: Productive Programming in Java 8 - with Lambdas and Streams

Parallel code

Serial code

Page 83: Productive Programming in Java 8 - with Lambdas and Streams

long numOfPrimes = LongStream.rangeClosed(2, 100_000) .filter(PrimeNumbers::isPrime) .count();

System.out.println(numOfPrimes);

Prints 9592

2.510 seconds

Page 84: Productive Programming in Java 8 - with Lambdas and Streams

Parallel code

Serial code

Let’s flip the switch by calling parallel() function

Page 85: Productive Programming in Java 8 - with Lambdas and Streams

long numOfPrimes = LongStream.rangeClosed(2, 100_000) .parallel() .filter(PrimeNumbers::isPrime) .count();

System.out.println(numOfPrimes);

Prints 9592

1.235 seconds

Page 86: Productive Programming in Java 8 - with Lambdas and Streams

Wow! That’s an awesome flip switch!

Page 87: Productive Programming in Java 8 - with Lambdas and Streams

Internally, parallel streams make use of fork-join framework

Page 88: Productive Programming in Java 8 - with Lambdas and Streams
Page 89: Productive Programming in Java 8 - with Lambdas and Streams

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

Gives wrong results with with parallel() call

Page 90: Productive Programming in Java 8 - with Lambdas and Streams

Adapt, learn functional programming!

Page 91: Productive Programming in Java 8 - with Lambdas and Streams

SOLID Principles and Design Patterns

Bootcamp - 25 JUN 2016 - Bangalore

Register here: https://www.townscript.com/e/designpattern

Fee Rs. 3500 Discount (Rs. 500)

code: “First10”

Page 92: Productive Programming in Java 8 - with Lambdas and Streams

Image credits• http://www.wetplanetwhitewater.com/images/uploads/adam_mills_elliott82.jpg • http://s.ecrater.com/stores/321182/53e46c705f68d_321182b.jpg • http://img.viralpatel.net/2014/01/java-lambda-expression.png • https://i.ytimg.com/vi/3C0R_fEXcYA/maxresdefault.jpg • http://farm1.static.flickr.com/74/170765090_53762a686c.jpg • http://www.monazu.com/wp-content/uploads/2012/06/ask-the-right-questions.jpg • https://s-media-cache-ak0.pinimg.com/736x/43/42/8a/43428ac2c352166374d851e895ed5db1.jpg • http://cdn.attackofthecute.com/August-17-2011-12-36-23-peekaboo-

kitty-46f32anul-131384-530-410.jpeg • https://ludchurchmyblog.files.wordpress.com/2010/02/myths-legend-pictures-083.jpg • http://www.youramazingplaces.com/wp-content/uploads/2013/06/Mauvoisin-Dam-

Switzerland-620x413.jpg • http://www.welikeviral.com/files/2014/08/Image-914.jpg • http://geekandpoke.typepad.com/.a/6a00d8341d3df553ef013485f6be4d970c-800wi • https://qph.fs.quoracdn.net/main-qimg-56547c0506050206b50b80a268bf2a84 • https://i.ytimg.com/vi/kCVsKsgVhBA/maxresdefault.jpg • http://i.livescience.com/images/i/000/022/395/original/man-dreams-bed.jpg • https://static-secure.guim.co.uk/sys-images/Guardian/Pix/pictures/2012/11/26/1353952826063/Alarm-

clock-010.jpg