java 8 - project lambda

Post on 10-May-2015

752 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

Short presentation of lambdas and the Stream API coming in java 8. For more in depth details see my blog: http://ivarconr.wordpress.com

TRANSCRIPT

Java 8 :: Project Lambda

λIvar Conradi Østhus

ico@finn.no

1 / 31

Java 8 - a few new (important) featuresLambda expressions

greater impact than generics in Java 1.5Stream APIDefault methods in interfacesCompact ProfilesNashorn JavaScript EngineMore annotationsParallel Array Sorting(new) Date & Time APIConcurrency Updates...Scheduled for March 2014

Complete list: http://openjdk.java.net/projects/jdk8/features

2 / 31

Warning:

a lot of code examples in this presentation!

3 / 31

Imperative style: for each element

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

//1: old loopfor(int i = 0; i < numbers.size(); i++) { System.out.println(i);}

//2: enhanced for-loopfor(Integer n : numbers) { System.out.println(n);}

4 / 31

Declarative style: for each element

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

public interface Iterable<T> { ... void forEach(Consumer<? super T> action); ...}

With anonymous inner class:

numbers.forEach(new Consumer<Integer>() { public void accept(Integer number) { System.out.println(number); }});

With lambda expression:

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

5 / 31

What is a functional interfaces?

@FunctionalInterfacepublic interface Predicate<T> { boolean test(T t);}

one abstract unimplemented methodoptional @FunctionalInterface annotationalready a lot of functional interfaces in javaJava API will be full of functional interfaces

6 / 31

Functional interfaces added in Java 8

Consumer<T> //takes an input T and performs an operation on it.

Supplier<T> //a kind of factory, will return a new or existing instance.

Predicate<T>//Checks if argument T satisfies a requirement.

Function<T, R> //Transform an argument from type T to type R.

7 / 31

Methods taking a functional interface will accept:

an anonymous inner classa lambda expressiona method reference

8 / 31

Lambda: typesSingle expression

(Integer i) -> i * 2;

Statement block

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

//multiple lines of code(int n) -> { int value = n*2; return value;};

9 / 31

Lambda: type inference

(Integer i) -> i * 2;

(i) -> i * 2;

i -> i*2;

//Multiple params(int x, int y) -> x + y

(x, y) -> x + y

10 / 31

Reuse lambdas

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

Function

public static Consumer<Integer> consumer() { return (Integer n) -> System.out.println(n);}

numbers.forEach(consumer());

Variable

public Consumer<Integer> consumer = (Integer n) -> System.out.println(n);

numbers.forEach(consumer);

11 / 31

Method reference

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

//Lambdanumbers.forEach(n -> System.out.println(n));

//Method referencenumbers.forEach(System.out::println);

12 / 31

Lambda summary

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

(x, y) -> x + y

x -> x + x

() -> x

enables better librariesuses lexical scopingrequires effectively final

13 / 31

The Java Stream API

14 / 31

Task: Double and sum all even numbers

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

Imperative solution

int sumOfDoubledEvenNbrs = 0;for(int number : numbers) { if(number % 2 == 0) { sumOfDoubledEvenNbrs += number * 2; }}

Declarative solution

int sum = numbers.stream() .filter(n -> n % 2 == 0) .mapToInt(n -> n * 2) .sum();

15 / 31

The Java Stream APIIntegration of lambda expressions with the Collection API'sAn abstraction for specifying aggregate computation on data setStreams are like iterators, yield elements for processingStreams can be finite and infiniteIntention: replace loops for aggregate operations

Streams gives us:

more readable codemore composable operationsparallizable

Think of Stream pipelines as builders:

have stream sourceadd many intermediate operationsexecute pipeline ONCE

Side note: Pipes in linux

cat index.html | tr "[A-Z]" "[a-z]" | grep lambda | sort

16 / 31

Source

collections, arrays, generator functions, IOcan be finite or infinitedo NOT modify the source during query

Intermediate operations

filter, map, mapToInt, flatMap, sorted, distinct, limit...stateless or statefulllazy -- returns new streamslambdas used to transform or drop values

Terminal operation

Aggregation: toArray, toList, reduce, sum, min, max, count, anyMatch, allMatchIteration: forEachSearching: findFirst, findAnyproduces a result / side-effect

17 / 31

Stream: sourcesCollections

List<Person> persons = new ArrayList<>();

Stream<Person> personStream = persons.stream();

IO

Stream<String> lineStream = bufferedReader.lines();

Stream factories

//rangeIntStream numbers = IntStream.range(0, 10);

//random numbersDoubleStream randomDoubles = new Random().doubles();

IntStream randomInts = new Random().ints(0, 10);

(Primitive streams are included for performance reasons)

18 / 31

Stream: intermediate operationsreturns a Stream, not elementsthey are lazy

filter

Stream<Person> stream = persons.stream().filter(p -> p.getAge() > 17);

map

Stream<String> stream = persons.stream().map(Person::getName);

mapToInt

IntStream stream3 = persons.stream().mapToInt(Person::getAge);

19 / 31

Stream: statefull intermediate operationsharder to parallelizeExamples: limit, substream, sorted, distinct

Stream<Person> sortedStream = persons.stream() .filter(p -> p.getAge() > 17) .sorted((p1, p2) -> p1.getAge() - p2.getAge());

20 / 31

Stream: terminal operationsreturn non-stream elementseager: force evaluation of the stream

Task: Find the average age in Sandnes

OptionalDouble average = persons.stream() .filter(p -> p.getCity().equals("Sandnes")) .mapToInt(p -> p.getAge()) .average();

(How would an imperative solution look like?)

21 / 31

Imperative solutionTask: Find the average age in Sandnes

int sum = 0;int count = 0;for(Person person : persons){ if(person.getCity().equals("Sandnes")) { sum += person.getAge(); count ++; }}double averageAgeInSandnes = (double)sum / count;

The Stream solution:

OptionalDouble average = persons.stream() .filter(p -> p.getCity().equals("Sandnes")) .mapToInt(p -> p.getAge()) .average();

22 / 31

Stream: Collectoraggregate values in to a containermany predefined collectors in java.util.stream.Collectors

countingaveraging/summarizing/sum/mintoList/toMap/toSetreducinggroupingBymapping

Collectors.toSet()

Set<String> names = persons.stream() .map(Person::getName) .collect(toSet());

Result:

[Ivar Østhus, Donald Duck, Ola Hansen, Kari Normann, Silje Hansen, Knerten Lillebror]

23 / 31

Stream: Collector - groupingByCollectors.groupingBy: age

Map<Integer, List<Person>> personsByAge = persons.stream().collect(groupingBy(Person::getAge));

groupingBy age, and only get their names

Map<Integer, List<String>> nameByAge = persons.stream() .collect(groupingBy(Person::getAge, mapping(Person::getName, toList())));

24 / 31

Stream the contents of a CSV fileMap persons in a CSV to a list of persons and return the 50 first adults.

name, age, city, countryIvar Østhus, 28, Oslo, NorwayViswanathan Anand, 43, Mayiladuthurai, IndiaMagnus Carlsen, 22, Tønsberg, Norway..

InputStream is = new FileInputStream(new File("persons.csv"));BufferedReader br = new BufferedReader(new InputStreamReader(is));

List<Person> persons = br.lines() .substream(1) .map(toPerson) .filter(isAdult) .limit(50) .collect(toList());

//lambdaspublic static Function<String, Person> toPerson = (line) -> { String[] p = line.split(", "); return new Person(p[0], Integer.parseInt(p[1]), p[2], p[3]);};public static Predicate<Person> isAdult = p -> p.getAge() > 17;

25 / 31

Parallel Streams

//SequentialOptionalDouble average = persons.stream() .filter(p -> p.getCity().equals("Sandnes")) .mapToInt(p -> p.getAge()) .average();

//ParallelOptionalDouble average = persons.parallelStream() .filter(p -> p.getCity().equals("Sandnes")) .mapToInt(p -> p.getAge()) .average();

26 / 31

Parallel Streams: visual model

(Source: https://oracleus.activeevents.com/2013/connect/sessionDetail.ww?SESSION_ID=7942)

27 / 31

Streams: performance

N = size of sourceQ = cost per-element through the pipelineN * Q ~= cost of pipeline

Larger N * Q → higher chance of good parallel performanceGenererally it is easier to know NFor small data sets → sequential usually winsComplex pipelines are harder to reason aboutWhat are the stream characteristics?Do not assume parallel is always faster!

MEASURE!!!

28 / 31

Interface: default methodsJava Collections Framework

designed fifteen years agowithout a functional orientationdo not have a method forEach, stream, ..

Until now adding new methods to an interface has been impossible without forcingmodification to existing classes

Solution: default methods in interfaces(also called virtual extension methods or defender methods)

A clever way to enhance existing interfaces with new methods

interface Iterator { // existing method declarations default void skip() { if (hasNext()) next(); }}

29 / 31

Stream API: summarySources:

Collections, Generator functions, IO

Intermediate functions:filter, map, sorted, limitlazy

Terminal operations:sum, max, min, collect, groupingByeager

30 / 31

Books:

Functional Programming in Java Vankat Subramaniam

Java 8 Lambdas in Action Raoul-Gabriel Urma, Mario Fusco, and AlanMycroft

Presentations:

https://oracleus.activeevents.com/2013/connect/sessionDetail.ww?SESSION_ID=7942https://oracleus.activeevents.com/2013/connect/sessionDetail.ww?SESSION_ID=7504http://www.slideshare.net/jaxlondon2012/lambda-a-peek-under-the-hood-brian-goetz

Videos:

http://parleys.com/channel/5243df06e4b0d1fb3c78fe31/presentations?sort=date&state=public

31 / 31

top related