java 8 stream api

of 45/45
Java 8 Stream API Raj Thavamani Application Developer / Java Group Biomedical Informatics

Post on 24-Feb-2016

268 views

Category:

Documents

15 download

Embed Size (px)

DESCRIPTION

Java 8 Stream API. Raj Thavamani Application Developer / Java Group Biomedical Informatics . Outline. Stream Building Blocks Java 8 Default Methods Functional Interfaces Lambda Expressions Method References. Outline. Characteristics of Streams Creating Streams - PowerPoint PPT Presentation

TRANSCRIPT

PowerPoint Presentation

Java 8 Stream APIRaj ThavamaniApplication Developer / Java GroupBiomedical Informatics

OutlineStream Building BlocksJava 8Default MethodsFunctional InterfacesLambda ExpressionsMethod References

OutlineCharacteristics of StreamsCreating StreamsCommon Functional Interfaces UsedAnatomy of the Stream pipelineOptional ClassCommon Stream API Methods UsedExamplesParallel StreamsUnbounded (On the Fly) StreamsWhat Could Streams Do For BMIReferencesQuestions?

Java 8Target Release Date: 03/18/14Introduces Default MethodsFunctional InterfacesLambda ExpressionsStream API and overall improvements to Collections to support Streams

Default MethodsIn Context of Support For StreamsJava 8 needed to add functionality to existing Collection interfaces to support Streams (stream(), forEach())

Default MethodsProblemPre-Java 8 interfaces couldnt have method bodies.The only way to add functionality to Interfaces was to declare additional methods which would be implemented in classes that implement the interfaceIt is impossible to add methods to an interface without breaking the existing implementation

Default MethodsSolutionDefault Methods!Java 8 allows default methods to be added to interfaces with their full implementationClasses which implement the interface dont have to have implementations of the default methodAllows the addition of functionality to interfaces while preserving backward compatibility

Default MethodsExamplepublic interface A {default void foo(){ System.out.println("Calling A.foo()");}

public class Clazz implements A {}

Clazz clazz = new Clazz();clazz.foo(); // Calling A.foo()

Functional InterfacesInterfaces with only one abstract method.With only one abstract method, these interfaces can be easily represented with lambda [email protected] interface SimpleFuncInterface {public void doWork();}

Lambda expressionsA more brief and clearly expressive way to implement functional interfaces Format: -> Example (Functional Interface)public interface Predicate {boolean test(T input);}Example (Static Method)public static Collection filter(Predicate predicate,Collection items) {Collection result = new ArrayList();for(T item: items) {if(predicate.test(item)) {result.add(item);}}} Example (Call with Lambda Expression)Collection myInts = asList(0,1,2,3,4,5,6,7,8,9);Collection onlyOdds = filter(n -> n % 2 != 0, myInts)Method ReferencesEvent more brief and clearly expressive way to implement functional interfacesFormat: ::Example (Functional Interface)public interface IntPredicates {boolean isOdd(Integer n) { return n % 2 != 0; }}Example (Call with Lambda Expression)List numbers = asList(1,2,3,4,5,6,7,8,9);List odds = filter(n -> IntPredicates.isOdd(n), numbers);Example (Call with Method Reference)List numbers = asList(1,2,3,4,5,6,7,8,9);List odds = filter(IntPredicates::isOdd, numbers);Characteristics of StreamsStreams are not related to InputStreams, OutputStreams, etc. Streams are NOT data structures but are wrappers around Collection that carry values from a source through a pipeline of operations.Streams are more powerful, faster and more memory efficient than ListsStreams are designed for lambdasStreams can easily be output as arrays or listsStreams employ lazy evaluationStreams are parallelizableStreams can be on-the-fly

Creating StreamsFrom individual values Stream.of(val1, val2, )From array Stream.of(someArray) Arrays.stream(someArray)From List (and other Collections)someList.stream()someOtherCollection.stream()

Common Functional Interfaces UsedPredicateRepresents a predicate (boolean-valued function) of one argumentFunctional method is boolean Test(T t)Evaluates this Predicate on the given input argument (T t)Returns true if the input argument matches the predicate, otherwise falseSupplierRepresents a supplier of resultsFunctional method is T get()Returns a result of type T

FunctionRepresents a function that accepts one argument and produces a resultFunctional method is R apply(T t)Applies this function to the given argument (T t) Returns the function resultConsumerRepresents an operation that accepts a single input and returns no resultFunctional method is void accept(T t)Performs this operation on the given argument (T t)

Common Functional Interfaces UsedFunctionRepresents an operation that accepts one argument and produces a resultFunctional method is R apply(T t)Applies this function to the given argument (T t) Returns the function result UnaryOperatorRepresents an operation on a single operands that produces a result of the same type as its operandFunctional method is R Function.apply(T t)Applies this function to the given argument (T t) Returns the function result

Common Functional Interfaces UsedBiFunctionRepresents an operation that accepts two arguments and produces a resultFunctional method is R apply(T t, U u)Applies this function to the given arguments (T t, U u) Returns the function result BinaryOperatorExtends BiFunctionRepresents an operation upon two operands of the same type, producing a result of the same type as the operandsFunctional method is R BiFunction.apply(T t, U u)Applies this function to the given arguments (T t, U u) where R,T and U are of the same typeReturns the function result ComparatorCompares its two arguments for order. Functional method is int compareTo(T o1, T o2)Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Anatomy of the Stream PipelineA Stream is processed through a pipeline of operationsA Stream starts with a source data structureIntermediate methods are performed on the Stream elements. These methods produce Streams and are not processed until the terminal method is called.The Stream is considered consumed when a terminal operation is invoked. No other operation can be performed on the Stream elements afterwardsA Stream pipeline contains some short-circuit methods (which could be intermediate or terminal methods) that cause the earlier intermediate methods to be processed only until the short-circuit method can be evaluated.

Anatomy of the Stream PipelineIntermediate Methodsmap, filter, distinct, sorted, peek, limit, parallelTerminal MethodsforEach, toArray, reduce, collect, min,max, count, anyMatch, allMatch, noneMatch, findFirst, findAny, iteratorShort-circuit MethodsanyMatch, allMatch, noneMatch, findFirst, findAny,limit

Optional ClassA container which may or may not contain a non-null valueCommon methodsisPresent() returns true if value is presentGet() returns value if presentorElse(T other) returns value if present, or otherifPresent(Consumer) runs the lambda if value is present

Common Stream API Methods UsedVoid forEach(Consumer)Easy way to loop over Stream elementsYou supply a lambda for forEach and that lambda is called on each element of the StreamRelated peek method does the exact same thing, but returns the original Stream

Common Stream API Methods UsedVoid forEach(Consumer)ExampleEmployees.forEach(e -> e.setSalary(e.getSalary() * 11/10))

Give all employees a 10% raise

Common Stream API Methods UsedVoid forEach(Consumer)Vs. For LoopsList employees = getEmployees();for(Employee e: employees) {e.setSalary(e.getSalary() * 11/10);}Advantages of forEachDesigned for lambdas to be marginally more succinctLambdas are reusableCan be made parallel with minimal effort

Common Stream API Methods UsedStream map(Function)Produces a new Stream that is the result of applying a Function to each element of original StreamExampleIds.map(EmployeeUtils::findEmployeeById)Create a new Stream of Employee ids

Common Stream API Methods UsedStream filter(Predicate)Produces a new Stream that contains only the elements of the original Stream that pass a given testExampleemployees.filter(e -> e.getSalary() > 100000)Produce a Stream of Employees with a high salary

Common Stream API Methods UsedOptional findFirst()Returns an Optional for the first entry in the StreamExampleemployees.filter().findFirst().orElse(Consultant)

Get the first Employee entry that passes the filter

Common Stream API Methods UsedObject[] toArray(Supplier)Reads the Stream of elements into a an arrayExampleEmployee[] empArray = employees.toArray(Employee[]::new);

Create an array of Employees out of the Stream of Employees

Common Stream API Methods UsedList collect(Collectors.toList())Reads the Stream of elements into a List or any other collectionExampleList empList =employees.collect(Collectors.toList());

Create a List of Employees out of the Stream of Employees

Common Stream API Methods UsedList collect(Collectors.toList())partitioningByYou provide a Predicate. It builds a Map where true maps to a List of entries that passed the Predicate, and false maps to a List that failed the Predicate.ExampleMap richTable =googlers().collect(partitioningBy(e -> e.getSalary() > 1000000));groupingByYou provide a Function. It builds a Map where each output value of the Function maps to a List of entries that gave that value.ExampleMap deptTable =employeeStream().collect(groupingBy(Employee::getDepartment));

Common Stream API Methods UsedT reduce(T identity, BinaryOperator)You start with a seed (identity) value, then combine this value with the first Entry in the Stream, combine the second entry of the Stream, etc.ExampleNums.stream().reduce(1, (n1,n2) -> n1*n2)

Calculate the product of numbersIntStream (Stream on primative int] has build-in sum()Built-in Min, Max methods

Common Stream API Methods UsedStream limit(long maxSize)Limit(n) returns a stream of the first n elementsExamplesomeLongStream.limit(10)

First 10 elementsCommon Stream API Methods UsedStream skip(long n)skip(n) returns a stream starting with element nExampletwentyElementStream.skip(5)

Last 15 elements

Common Stream API Methods UsedStream sorted(Comparator)Returns a stream consisting of the elements of this stream, sorted according to the provided ComparatorExampleempStream.map().filter().limit().sorted((e1, e2) -> e1.getSalary() - e2.getSalary())

Employees sorted by salary

Common Stream API Methods UsedOptional min(Comparator)Returns the minimum element in this Stream according to the ComparatorExampleEmployee alphabeticallyFirst =ids.stream().map(EmployeeSamples::findGoogler).min((e1, e2) ->e1.getLastName().compareTo(e2.getLastName())).get();

Get Googler with earliest lastName

Common Stream API Methods UsedOptional max(Comparator)Returns the minimum element in this Stream according to the ComparatorExampleEmployee richest =ids.stream().map(EmployeeSamples::findGoogler).max((e1, e2) -> e1.getSalary() -e2.getSalary()).get();

Get Richest Employee

Common Stream API Methods UsedStream distinct()Returns a stream consisting of the distinct elements of this streamExampleList ids2 =Arrays.asList(9, 10, 9, 10, 9, 10);List emps4 =ids2.stream().map(EmployeeSamples::findGoogler).distinct().collect(toList());

Get a list of distinct Employees

Common Stream API Methods UsedBoolean anyMatch(Predicate), allMatch(Predicate), noneMatch(Predicate)Returns true if Stream passes, false otherwiseLazy EvaluationanyMatch processes elements in the Stream one element at a time until it finds a match according to the Predicate and returns true if it found a matchallMatch processes elements in the Stream one element at a time until it fails a match according to the Predicate and returns false if an element failed the PredicatenoneMatch processes elements in the Stream one element at a time until it finds a match according to the Predicate and returns false if an element matches the PredicateExampleemployeeStream.anyMatch(e -> e.getSalary() > 500000)

Is there a rich Employee among all Employees?

Common Stream API Methods Usedlong count()Returns the count of elements in the StreamExampleemployeeStream.filter(somePredicate).count()

How many Employees match the criteria?

Parallel StreamsHelper Methods For Timingprivate static void timingTest(Stream testStream) {long startTime = System.nanoTime();testStream.forEach(e -> doSlowOp());long endTime = System.nanoTime();System.out.printf(" %.3f seconds.%n",deltaSeconds(startTime, endTime));}

private static double deltaSeconds(long startTime,long endTime) {return((endTime - startTime) / 1000000000);}

Parallel StreamsHelper Method For Simulating Long Operation

void doSlowOp() {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException ie) {// Nothing to do here.}}Parallel StreamsMain CodeSystem.out.print("Serial version [11 entries]:");timingTest(googlers());int numProcessorsOrCores =Runtime.getRuntime().availableProcessors();System.out.printf("Parallel version on %s-core machine:",numProcessorsOrCores);timingTest(googlers().parallel() );

Parallel StreamsResultsSerial version [11 entries]: 11.000 seconds.Parallel version on 4-core machine: 3.000 seconds.

(On The Fly) StreamsStream generate(Supplier)The method lets you specify a SupplierThis Supplier is invoked each time the system needs a Stream elementExampleList emps =Stream.generate(() -> randomEmployee()).limit(n).collect(toList());

Stream iterate(T seed, UnaryOperator f)The method lets you specify a seed and a UnaryOperator.The seed becomes the first element of the Stream, f(seed) becomes the second element of the Stream, f(second) becomes the third element, etc.ExampleList powersOfTwo =Stream.iterate(1, n -> n * 2).limit(n).collect(toList());The values are not calculated until they are neededTo avoid unterminated processing, you must eventually use a size-limiting methodThis is less of an actual Unbounded Stream and more of an On The Fly Stream

What Could Streams do For BMI?The real excitement with Streams is when you combine Stream operators into one pipelineParallel Processing on large Patient SetsTaking advantage of groupingBy and partitioningBy to perform analysisExample1: PvpPatientPicker for ICNA massive datatable that needs to have the ability to filter on any column as well as do nested filteringThink of how much code you would need to implement the filteringUsing Streams:List pvpPatients = .List filteredPvpPatients =Stream.of(PvpPatients).parallel().map(PvpPatient::findByPatientNumber).filter(pvpPatient -> pvpPatient.ProviderId == 101).filter(pvpPatient -> pvpPatient.careStratificationScore == 10).collect(Collectors.toList()); Example2: QueryTool for i2b2Using Streams:Map patientsByRace =patientStream().collect(groupingBy(Patient::getRace));ReferencesStream APIhttp://download.java.net/jdk8/docs/api/java/util/stream/Stream.htmlJava 8 Explained: Applying Lambdas to Java Collectionshttp://zeroturnaround.com/rebellabs/java-8-explained-applying-lambdas-to-java-collections/Java 8 first steps with Lambdas and Streamshttps://blog.codecentric.de/en/2013/10/java-8-first-steps-lambdas-streams/Java 8Tutorial: Lambda Expressions, Streams, and Morehttp://www.coreservlets.com/java-8-tutorial/

Questions?