Computer Science 312 Composing Functions Streams in Java 1
Composing Functions into a Pipeline In Haskell: rightToLeftComposition x = f (g x) rightToLeftComposition x = f $ g $ x rightToLeftComposition = f . g $ is the apply operator (does left to right without parentheses) . is the composition operator (builds a new function)
Composing Comparisons for sort By ascending order of weight: inventory.sort(comparing(Apple::getWeight));
Composing Comparisons for sort By descending order of weight: inventory.sort(comparing(Apple::getWeight).reversed());
Composing Comparisons for sort By descending order of weight, and then by country if they have the same weight: inventory.sort(comparing(Apple::getWeight) .reversed() .thenComparing(Apple::getCountry));
Composing Predicates Can negate a predicate: Predicate<Apple> notRedApple = redApple.negate();
Composing Predicates Can negate a predicate: Can AND two predicates: Predicate<Apple> notRedApple = redApple.negate(); Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);
Composing Predicates Can negate a predicate: Can AND two predicates: Can OR two predicates: Predicate<Apple> notRedApple = redApple.negate(); Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150); Predicate<Apple> redAndHeavyOrMacintoshApple = redApple.and(a -> a.getWeight() > 150) .or(a -> a.getType() == MACINTOSH);
Composing Functions Use andThen to compose two functions for left- to-right pipelining T is the argument type of f1 and U is the result type of f2 The result type of f1 must match the argument type of f2 Function<T, U> pipelinedF = f1.andThen(f2);
Pipelined Functions Example public class Letter{ public static String addHeader(String text){ return "From Raoul, Mario and Alan: " + text; } public static String addFooter(String text){ return text + " Kind regards"; public static String checkSpelling(String text){ return text.replaceAll("labda", "lambda");
Pipelined Functions Example Function<String, String> addHeader = Letter::addHeader; Function<String, String> transformationPipeline = addHeader.andThen(Letter::checkSpelling) .andThen(Letter::addFooter); Functions are chained and evaluated from left to right
andThen vs compose Use andThen for left-to-right composition: Use compose for right-to-left composition:
What Are Streams? A stream is an abstraction of a sequence of data Each data value is provided on demand Unlike collections, streams can be lazy (even infinite) Like video streaming vs a DVD
Streams vs Collections Collections are used to store and manage data Streams are used to process these data Stream processing Hides procedural details of iteration Supports optimizations like parallel processing
Example: Get the Names of Low Calorie Dishes
Example: Get the Names of Low Calorie Dishes
What’s Needed for Data Processing A data source on which to open a stream A set of intermediate operations to transform these data (map, filter, sorted, etc.) A terminal operation (collect, count, etc.) to collect the results
Get Source, Process, and Collect Print the names of the first three high-calorie dishes
Get Source, Process, and Collect
Internal vs External Iteration The for loop over a collection is an example of external iteration Must visit every item in an eager manner Streams support internal iteration Visit items in a lazy manner, only as needed Intermediate operations can be merged as their results are collected by the terminal operation Processing can be parallelized
Which Operations Are Intermediate and Which Are Terminal? long count = menu.stream() .filter(d -> d.getCalories() > 300) .distinct() .limit(3) .count();
Parallelize! sortedBigData = bigData.parallelStream() .sorted() .collect(toList());
Intermediate operations Chapter 5 For next time Intermediate operations Chapter 5