Java 8 - project lambda
-
Upload
ivar-osthus -
Category
Technology
-
view
746 -
download
4
Embed Size (px)
description
Transcript of Java 8 - project lambda

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