Functional Programming in Java 8 Omar Bashir
Interfaces
Default Methods ● Methods implemented in interfaces that are available to all their implementations. – Removes the need to provide a common implementation either in every class implementing the interface or in a common base class implementation. – Makes existing interface implementations future-proof. ● Interface implementations can override default implementations. ● Non-final methods in the Object base class cannot be overridden by default methods.
Default Methods (Example) ● An instrumentation interface for vehicles. – Methods ● Return trip distance. ● Return trip time. ● Default method to return average speed by dividing the trip distance by the trip time. ● Implementations – Aircraft instrumentation to which leg distances with corresponding times are added. – Car instrumentation to which distance travelled in hourly intervals is added. – Statue instrumentation that returns 0 for all methods.
Instrumentation Interface public interface Instrumentation { double getTripDistance(); double getTripTime(); default double getAverageSpeed() { return getTripDistance()/getTripTime(); } }
CarInstrumentation public class CarInstrumentation implements Instrumentation { private final List<Double> samples; public CarInstrumentation() { samples = new ArrayList<>(); } public void addSample(double distance) { samples.add(distance); } @Override public double getTripDistance() { double sum = 0.0; for(double value : samples) { sum += value; } return sum; } @Override public double getTripTime() { return samples.size(); } }
AircraftInstrumentation public class AircraftInstrumentation implements Instrumentation { private final List<Double> legTimes; private final List<Double> legDistances; public AircraftInstrumentation() { legTimes = new ArrayList<>(); legDistances = new ArrayList<>(); } public void addLeg(double legDistance, double legTime) { legTimes.add(legTime); legDistances.add(legDistance); } private double add(List<Double> data) { double sum = 0.0; for(double value : data) { sum += value; } return sum; } @Override public double getTripDistance() { return add(legDistances); } @Override public double getTripTime() { return add(legTimes); } }
Statue Interface public class StatueInstrumentation implements Instrumentation { @Override public double getTripDistance() { return 0; } @Override public double getTripTime() { return 0; } @Override public double getAverageSpeed() { return 0; } }
Example public static void main(String[] args) { System.out.printf("Statue speed = %.2fn", new StatueInstrumentation().getAverageSpeed()); CarInstrumentation carInst = new CarInstrumentation(); carInst.addSample(50); carInst.addSample(70); carInst.addSample(60); System.out.printf("Car speed = %.2fn", carInst.getAverageSpeed()); AircraftInstrumentation planeInst = new AircraftInstrumentation(); planeInst.addLeg(70, 1.5); planeInst.addLeg(25, 0.25); planeInst.addLeg(75, 1.25); planeInst.addLeg(110, 1); System.out.printf("Plane speed = %.2fn", planeInst.getAverageSpeed()); }
Default Methods ● With great power comes great responsibility. – Developers may be tempted to extend existing implementations using default methods. ● This may require overriding default methods in some interface implementation to accommodate specifics of implementations. – Ideally, default methods should ● contain common functionality across interface implementations. ● contain functionality that can be defined in terms of the abstract methods. – If overriding default methods becomes common, these may be converted to abstract methods.
Static Methods ● Similar to static methods in classes. ● Allows methods to be called without implementing an interface. ● Allows grouping of relevant utility methods with the corresponding interfaces. – No need to write utility companion classes., e.g., ● Static methods are not part of the implementing classes. ● To invoke, prefix the static method name with the name of the interface. ● Static methods can be invoked from default methods.
StaticMethods(Example) public interface Calculator { static double add(double a, double b) { return a + b; } static double subtract(double a, double b) { return a - b; } static double multiply(double a, double b) { return a * b; } static double divide(double a, double b) { return a / b; } } public static void main(String[] args) { double a = 5.0; double b = 2.5; System.out.println(Calculator.add(a, b)); System.out.println(Calculator.subtract(a, b)); System.out.println(Calculator.multiply(a, b)); System.out.println(Calculator.divide(a, b)); } Usage
Lambda Expressions
Anonymous Function Calls ● Syntax – parameter ­> expression – Translates to ● function(parameter) where function implementation contains the expression – Parameter syntax, ● Parenthesis optional only for single parameters in function call. ● Parameter types are optional. – Expression syntax ● Braces and return required for multi-line expressions. ● Expressions can be method references.
Functional Interfaces ● Specifying type of lambda expressions. – To assign lambda expressions to variables and used repeated. – To declare lambda expressions as function parameters. ● Standard Java interfaces with following exceptions, – Only one abstract method in the interface. ● SAM (Single Abstract Method) interfaces. – Can be decorated with annotation @FunctionalInterface for compiler to check that interface is SAM interface. ● Functional interfaces for common use cases already specified in java.util.function package. – Custom functional interfaces rarely required.
Lambda Expression - Example // BiFunction takes two arguments and returns the result. // The following statement effectively creates an anonymous // class implementing BiFunction where the apply method adds the // two arguments and returns the result. BiFunction<Integer, Integer, Integer> intAdder = (a, b) -> a + b; int op1 = 5; int op2 = 25; int sum = intAdder.apply(op1, op2); System.out.printf("%d + %d = %dn", op1, op2, sum);
Lambda Expression - Example public static void main(String[] args) { int op1 = 25; int op2 = 5; int sum = process(op1, op2, (a, b) -> a + b); int diff = process(op1, op2, (a, b) -> a - b); int product = process(op1, op2, (a, b) -> a * b); int div = process(op1, op2, (a, b) -> a / b); System.out.printf("%d + %d = %dn", op1, op2, sum); System.out.printf("%d - %d = %dn", op1, op2, diff); System.out.printf("%d * %d = %dn", op1, op2, product); System.out.printf("%d / %d = %dn", op1, op2, div); } private static int process( int x, int y, BiFunction<Integer, Integer, Integer> processor) { return processor.apply(x, y); }
Lambda Expression - Example public class FunctionalCalculator { public static void main(String[] args) { if (args.length == 3) { Map<String, BiFunction<Double, Double, Double>> calculator = new HashMap<>(); calculator.put("+", (a, b) -> a + b); calculator.put("-", (a, b) -> a - b); calculator.put("*", (a, b) -> a * b); calculator.put("/", (a, b) -> a / b); String operator = args[1]; if (calculator.containsKey(operator)) { Double operand1 = Double.parseDouble(args[0]); Double operand2 = Double.parseDouble(args[2]); double result = calculator.get(operator).apply(operand1, operand2); System.out.printf("%.2f %s %.2f = %.2f", operand1, operator, operand2, result); } else { System.out.printf("Operator %s not recognisedn", operator); System.out.println("Operators:: +, -, *, /"); } } else { System.out.println("USAGE:: Command line arguments operand1 operator operand2"); System.out.println("Operators:: +, -, *, /"); } } }
Closure ● Lambda expressions allow capturing variables and methods defined in their scope. – Lambda expressions close over the scope in which they exist. ● The state of the variables captured stay with the expressions even if they are passed to other methods and executed there. ● Captured variables are effectively final, i.e., – Mutating these values results in a compilation error.
Closure-Example public class WeightCalculator { final double mass; public WeightCalculator(double mass) { this.mass = mass; } public Function<Double, Double> getCalculator() { return g -> this.getWeight(mass, g); } private double getWeight(double m, double g) { return m * g; } } public static void main(String[] args) { double mass = 10; Function<Double, Double> calculator = new WeightCalculator(mass).getCalculator(); double weightOnEarth = calculator.apply(9.8); double weightOnMars = calculator.apply(3.77); System.out.printf("%.2f kg on Earth is %.2f N on Earthn", mass, weightOnEarth); System.out.printf("%.2f kg on Earth is %.2f N on Marsn", mass, weightOnMars); }
Method Referencing ● Obtaining the reference of a method so that – It can be assigned to a matching functional interface variable, – And that functional interface can be executed later. ● :: is the referencing operator. ● Applies to, – Static methods, e.g., ClassName::staticMethodName. – Instance methods, e.g., ObjectRef::instanceMethodName. – Constructors, e.g., ClassName::new.
MethodReferencing- Example public class Doubler { public static double doubleIt(double value) { return 2 * value; } } public static void main(String[] args) { Function<Double, Double> doubler = Doubler::doubleIt; Consumer<String> printer = System.out::println; Function<Double, Double> maker = Double::new; workIt(doubler, printer, maker, 3); } private static void workIt( Function<Double, Double> worker, Consumer<String> consumer, Function<Double, Double> creater, double value) { double result = worker.apply(value); consumer.accept(creater.apply(result).toString()); }
Optional
Optional ● Container class that may or may not contain a non- null value. ● Contains methods that – determine presence or absence of value. – perform operations based on presence or absence of a value. – operate on the contained value. ● Protects against NullPointerException.
Key Members ● Construction using static factory methods, – empty() ● returns an empty Optional instance. – of(T value)  ● returns an Optional instance with value. – ofNullable(T value) ● returns an Optional instance with the supplied value if non- nullable, an empty instance otherwise.
Key Members ● Accessors, – get()  ● returns contained value or throws NoSuchElementException if empty. – isPresent() ● returns true if not empty. – orElse(T other)  ● returns enclosed value if not empty otherwise returns other. – orElseGet(Supplier<? extends T> other) ● returns enclosed value if not empty otherwise calls other to get a value.
Key Members ● Transformation, consumer and filter, – ifPresent(Consumer<? super T> consumer)  ● calls consumer on value if present otherwise does nothing. – filter(Predicate<? super T> predicate)  ● returns this Optional if the value is present and predicate returns true otherwise returns empty Optional. – map(Function<? super T, ? extends U> mapper)  ● transforms the value using the mapper if present otherwise does nothing. – flatMap(Function<? super T, Optional<U>>  mapper) ● applies mapper to value and returns an Optional bearing transformed value.
Optional-Example /** * Find at matching name from the list and if present. print the value * after converting it into uppercase. * @param args */ public static void main(String[] args) { List<String> names = Arrays.asList("George Patton", "Omar Bradley", "Bernard Montgomery", "Erwin Romel"); Optional<String> name = find(names, "Brad"); name.map(x -> x.toUpperCase()).ifPresent(x -> System.out.println(x)); System.out.println("DONE"); } private static Optional<String> find(List<String> names, String value) { Optional<String> result = Optional.empty(); boolean found = false; Iterator<String> itr = names.iterator(); while (!found && itr.hasNext()) { String item = itr.next(); if (item.contains(value)) { found = true; result = Optional.of(item); } } return result; }
Streams
Streams ● An abstraction allowing generic and declarative processing of collections. ● Operations on streams are – Intermediate operations ● Return a stream object representing intermediate results. ● Allow chaining of operations. – Terminal operations ● Either perform a void operation or return a non-stream result. ● Immutable operations – Original data source is not modified.
Streams ● Obtaining a stream on a collection, – stream() to return a sequential stream. – parallelStream() to create a stream capable of executing in multiple threads. ● Streams evaluated lazily, – Once a terminal operation is executed. ● Streams cannot be reused, – Once a terminal operation executed, the stream is closed. – Call get() on the stream before calling a terminal operation to get a copy of the stream.
Streams - Example public class Finder { /** * Find at matching name from the list and if present. print the * value after converting it into uppercase. * @param args */ public static void main(String[] args) { List<String> names = Arrays.asList("George Patton", "Omar Bradley", "Bernard Montgomery", "Erwin Romel"); Optional<String> name = names.stream(). filter(x -> x.contains("Bernard")).findFirst(); name.map(x -> x.toUpperCase()). ifPresent(x -> System.out.println(x)); System.out.println("Done"); } }
Collectors ● Implementation of the Collector interface. ● Performs useful reduction operations on stream, e.g., – Accumulation of elements into collections, – Summarising values, – Grouping, – Partitioning ● Typically used in the collect method of the stream to return the final collection after the stream pipeline has executed.
Collectors - Example /** * Return a list of even numbers from a list of string * representation of integers. * @param args */ List<String> numStr = Arrays.asList("53", "26", "33", "77", "2", "8", "9", "98"); List<Integer> evenNums = numStr.stream(). map(x -> Integer.parseInt(x)). filter(x -> x % 2 == 0). collect(Collectors.toList()); evenNums.forEach(System.out::println);
Stream Reduction - Example List<Double> nums = Arrays.asList(25.5, 23.25, 17.0, 9.25); /* * reduce takes an initial accumulator value and a BiFunction * extension that takes the accumulated value, iteratively adds * the elements in the stream. */ double average = nums.stream(). reduce(0.0, (acc, x) -> acc + x)/nums.size(); System.out.printf("Average = %.3f", average);
Collector Reduction - Example List<Double> nums = Arrays.asList(25.5, 23.25, 17.0, 9.25); double average = nums.stream(). collect(Collectors.averagingDouble(x -> x)); System.out.printf("Average = %.3f", average);
Creating Streams ● static Stream<T> of(T... values) – Creates a stream of values specified. ● static  IntStream range(int inclusiveStart,  int exclusiveEnd) – Sequentially ordered stream of integers with increment of 1 excluding the end value. ● static IntStream rangeClosed(int  inclusiveStart, int inclusiveEnd) – Sequentially ordered stream of integers with increment of 1 including the end value.
IntStream - Example IntStream range = IntStream.rangeClosed(1, num); int factorial = range.reduce(1, (acc, x) -> acc * x); System.out.printf("%d! = %dn", num, factorial);
flatMap
flatMap ● Consider a collection of collections of items. – flatMap used to transform items of inner collections. – and then flatten the collection of collections of transformed items to a collection of transformed items. ● Defined for – Stream, – Optional
Example – Stream flatMap List<List<String>> linesOfWords = Arrays.asList(Arrays.asList("Incy", "wincy", "spider"), Arrays.asList("Climbing", "up", "the", "spout")); Stream<String> dataStream = linesOfWords.stream(). flatMap(line -> line.stream().map(word -> word.toUpperCase())); List<String> data = dataStream.collect(Collectors.toList()); data.forEach(System.out::println); INCY WINCY SPIDER CLIMBING UP THE SPOUT
Example – Flattening Optional Collections List<Optional<Integer>> nums = Arrays.asList(Optional.of(3), Optional.of(5), Optional.empty(), Optional.of(9)); System.out.println(nums); List<Integer> filteredNums = nums.stream(). filter(n -> n.isPresent()). map(n -> n.get()). collect(Collectors.toList()); System.out.println(filteredNums); [Optional[3], Optional[5], Optional. empty, Optional[9]] [3, 5, 9]

Functional Programming in Java 8

  • 1.
    Functional Programming inJava 8 Omar Bashir
  • 2.
  • 3.
    Default Methods ● Methodsimplemented in interfaces that are available to all their implementations. – Removes the need to provide a common implementation either in every class implementing the interface or in a common base class implementation. – Makes existing interface implementations future-proof. ● Interface implementations can override default implementations. ● Non-final methods in the Object base class cannot be overridden by default methods.
  • 4.
    Default Methods (Example) ●An instrumentation interface for vehicles. – Methods ● Return trip distance. ● Return trip time. ● Default method to return average speed by dividing the trip distance by the trip time. ● Implementations – Aircraft instrumentation to which leg distances with corresponding times are added. – Car instrumentation to which distance travelled in hourly intervals is added. – Statue instrumentation that returns 0 for all methods.
  • 5.
    Instrumentation Interface public interfaceInstrumentation { double getTripDistance(); double getTripTime(); default double getAverageSpeed() { return getTripDistance()/getTripTime(); } }
  • 6.
    CarInstrumentation public class CarInstrumentationimplements Instrumentation { private final List<Double> samples; public CarInstrumentation() { samples = new ArrayList<>(); } public void addSample(double distance) { samples.add(distance); } @Override public double getTripDistance() { double sum = 0.0; for(double value : samples) { sum += value; } return sum; } @Override public double getTripTime() { return samples.size(); } }
  • 7.
    AircraftInstrumentation public class AircraftInstrumentationimplements Instrumentation { private final List<Double> legTimes; private final List<Double> legDistances; public AircraftInstrumentation() { legTimes = new ArrayList<>(); legDistances = new ArrayList<>(); } public void addLeg(double legDistance, double legTime) { legTimes.add(legTime); legDistances.add(legDistance); } private double add(List<Double> data) { double sum = 0.0; for(double value : data) { sum += value; } return sum; } @Override public double getTripDistance() { return add(legDistances); } @Override public double getTripTime() { return add(legTimes); } }
  • 8.
    Statue Interface public classStatueInstrumentation implements Instrumentation { @Override public double getTripDistance() { return 0; } @Override public double getTripTime() { return 0; } @Override public double getAverageSpeed() { return 0; } }
  • 9.
    Example public static voidmain(String[] args) { System.out.printf("Statue speed = %.2fn", new StatueInstrumentation().getAverageSpeed()); CarInstrumentation carInst = new CarInstrumentation(); carInst.addSample(50); carInst.addSample(70); carInst.addSample(60); System.out.printf("Car speed = %.2fn", carInst.getAverageSpeed()); AircraftInstrumentation planeInst = new AircraftInstrumentation(); planeInst.addLeg(70, 1.5); planeInst.addLeg(25, 0.25); planeInst.addLeg(75, 1.25); planeInst.addLeg(110, 1); System.out.printf("Plane speed = %.2fn", planeInst.getAverageSpeed()); }
  • 10.
    Default Methods ● Withgreat power comes great responsibility. – Developers may be tempted to extend existing implementations using default methods. ● This may require overriding default methods in some interface implementation to accommodate specifics of implementations. – Ideally, default methods should ● contain common functionality across interface implementations. ● contain functionality that can be defined in terms of the abstract methods. – If overriding default methods becomes common, these may be converted to abstract methods.
  • 11.
    Static Methods ● Similarto static methods in classes. ● Allows methods to be called without implementing an interface. ● Allows grouping of relevant utility methods with the corresponding interfaces. – No need to write utility companion classes., e.g., ● Static methods are not part of the implementing classes. ● To invoke, prefix the static method name with the name of the interface. ● Static methods can be invoked from default methods.
  • 12.
    StaticMethods(Example) public interface Calculator{ static double add(double a, double b) { return a + b; } static double subtract(double a, double b) { return a - b; } static double multiply(double a, double b) { return a * b; } static double divide(double a, double b) { return a / b; } } public static void main(String[] args) { double a = 5.0; double b = 2.5; System.out.println(Calculator.add(a, b)); System.out.println(Calculator.subtract(a, b)); System.out.println(Calculator.multiply(a, b)); System.out.println(Calculator.divide(a, b)); } Usage
  • 13.
  • 14.
    Anonymous Function Calls ●Syntax – parameter ­> expression – Translates to ● function(parameter) where function implementation contains the expression – Parameter syntax, ● Parenthesis optional only for single parameters in function call. ● Parameter types are optional. – Expression syntax ● Braces and return required for multi-line expressions. ● Expressions can be method references.
  • 15.
    Functional Interfaces ● Specifyingtype of lambda expressions. – To assign lambda expressions to variables and used repeated. – To declare lambda expressions as function parameters. ● Standard Java interfaces with following exceptions, – Only one abstract method in the interface. ● SAM (Single Abstract Method) interfaces. – Can be decorated with annotation @FunctionalInterface for compiler to check that interface is SAM interface. ● Functional interfaces for common use cases already specified in java.util.function package. – Custom functional interfaces rarely required.
  • 16.
    Lambda Expression -Example // BiFunction takes two arguments and returns the result. // The following statement effectively creates an anonymous // class implementing BiFunction where the apply method adds the // two arguments and returns the result. BiFunction<Integer, Integer, Integer> intAdder = (a, b) -> a + b; int op1 = 5; int op2 = 25; int sum = intAdder.apply(op1, op2); System.out.printf("%d + %d = %dn", op1, op2, sum);
  • 17.
    Lambda Expression -Example public static void main(String[] args) { int op1 = 25; int op2 = 5; int sum = process(op1, op2, (a, b) -> a + b); int diff = process(op1, op2, (a, b) -> a - b); int product = process(op1, op2, (a, b) -> a * b); int div = process(op1, op2, (a, b) -> a / b); System.out.printf("%d + %d = %dn", op1, op2, sum); System.out.printf("%d - %d = %dn", op1, op2, diff); System.out.printf("%d * %d = %dn", op1, op2, product); System.out.printf("%d / %d = %dn", op1, op2, div); } private static int process( int x, int y, BiFunction<Integer, Integer, Integer> processor) { return processor.apply(x, y); }
  • 18.
    Lambda Expression -Example public class FunctionalCalculator { public static void main(String[] args) { if (args.length == 3) { Map<String, BiFunction<Double, Double, Double>> calculator = new HashMap<>(); calculator.put("+", (a, b) -> a + b); calculator.put("-", (a, b) -> a - b); calculator.put("*", (a, b) -> a * b); calculator.put("/", (a, b) -> a / b); String operator = args[1]; if (calculator.containsKey(operator)) { Double operand1 = Double.parseDouble(args[0]); Double operand2 = Double.parseDouble(args[2]); double result = calculator.get(operator).apply(operand1, operand2); System.out.printf("%.2f %s %.2f = %.2f", operand1, operator, operand2, result); } else { System.out.printf("Operator %s not recognisedn", operator); System.out.println("Operators:: +, -, *, /"); } } else { System.out.println("USAGE:: Command line arguments operand1 operator operand2"); System.out.println("Operators:: +, -, *, /"); } } }
  • 19.
    Closure ● Lambda expressionsallow capturing variables and methods defined in their scope. – Lambda expressions close over the scope in which they exist. ● The state of the variables captured stay with the expressions even if they are passed to other methods and executed there. ● Captured variables are effectively final, i.e., – Mutating these values results in a compilation error.
  • 20.
    Closure-Example public class WeightCalculator{ final double mass; public WeightCalculator(double mass) { this.mass = mass; } public Function<Double, Double> getCalculator() { return g -> this.getWeight(mass, g); } private double getWeight(double m, double g) { return m * g; } } public static void main(String[] args) { double mass = 10; Function<Double, Double> calculator = new WeightCalculator(mass).getCalculator(); double weightOnEarth = calculator.apply(9.8); double weightOnMars = calculator.apply(3.77); System.out.printf("%.2f kg on Earth is %.2f N on Earthn", mass, weightOnEarth); System.out.printf("%.2f kg on Earth is %.2f N on Marsn", mass, weightOnMars); }
  • 21.
    Method Referencing ● Obtainingthe reference of a method so that – It can be assigned to a matching functional interface variable, – And that functional interface can be executed later. ● :: is the referencing operator. ● Applies to, – Static methods, e.g., ClassName::staticMethodName. – Instance methods, e.g., ObjectRef::instanceMethodName. – Constructors, e.g., ClassName::new.
  • 22.
    MethodReferencing- Example public class Doubler{ public static double doubleIt(double value) { return 2 * value; } } public static void main(String[] args) { Function<Double, Double> doubler = Doubler::doubleIt; Consumer<String> printer = System.out::println; Function<Double, Double> maker = Double::new; workIt(doubler, printer, maker, 3); } private static void workIt( Function<Double, Double> worker, Consumer<String> consumer, Function<Double, Double> creater, double value) { double result = worker.apply(value); consumer.accept(creater.apply(result).toString()); }
  • 23.
  • 24.
    Optional ● Container classthat may or may not contain a non- null value. ● Contains methods that – determine presence or absence of value. – perform operations based on presence or absence of a value. – operate on the contained value. ● Protects against NullPointerException.
  • 25.
    Key Members ● Constructionusing static factory methods, – empty() ● returns an empty Optional instance. – of(T value)  ● returns an Optional instance with value. – ofNullable(T value) ● returns an Optional instance with the supplied value if non- nullable, an empty instance otherwise.
  • 26.
    Key Members ● Accessors, –get()  ● returns contained value or throws NoSuchElementException if empty. – isPresent() ● returns true if not empty. – orElse(T other)  ● returns enclosed value if not empty otherwise returns other. – orElseGet(Supplier<? extends T> other) ● returns enclosed value if not empty otherwise calls other to get a value.
  • 27.
    Key Members ● Transformation,consumer and filter, – ifPresent(Consumer<? super T> consumer)  ● calls consumer on value if present otherwise does nothing. – filter(Predicate<? super T> predicate)  ● returns this Optional if the value is present and predicate returns true otherwise returns empty Optional. – map(Function<? super T, ? extends U> mapper)  ● transforms the value using the mapper if present otherwise does nothing. – flatMap(Function<? super T, Optional<U>>  mapper) ● applies mapper to value and returns an Optional bearing transformed value.
  • 28.
    Optional-Example /** * Find atmatching name from the list and if present. print the value * after converting it into uppercase. * @param args */ public static void main(String[] args) { List<String> names = Arrays.asList("George Patton", "Omar Bradley", "Bernard Montgomery", "Erwin Romel"); Optional<String> name = find(names, "Brad"); name.map(x -> x.toUpperCase()).ifPresent(x -> System.out.println(x)); System.out.println("DONE"); } private static Optional<String> find(List<String> names, String value) { Optional<String> result = Optional.empty(); boolean found = false; Iterator<String> itr = names.iterator(); while (!found && itr.hasNext()) { String item = itr.next(); if (item.contains(value)) { found = true; result = Optional.of(item); } } return result; }
  • 29.
  • 30.
    Streams ● An abstractionallowing generic and declarative processing of collections. ● Operations on streams are – Intermediate operations ● Return a stream object representing intermediate results. ● Allow chaining of operations. – Terminal operations ● Either perform a void operation or return a non-stream result. ● Immutable operations – Original data source is not modified.
  • 31.
    Streams ● Obtaining astream on a collection, – stream() to return a sequential stream. – parallelStream() to create a stream capable of executing in multiple threads. ● Streams evaluated lazily, – Once a terminal operation is executed. ● Streams cannot be reused, – Once a terminal operation executed, the stream is closed. – Call get() on the stream before calling a terminal operation to get a copy of the stream.
  • 32.
    Streams - Example publicclass Finder { /** * Find at matching name from the list and if present. print the * value after converting it into uppercase. * @param args */ public static void main(String[] args) { List<String> names = Arrays.asList("George Patton", "Omar Bradley", "Bernard Montgomery", "Erwin Romel"); Optional<String> name = names.stream(). filter(x -> x.contains("Bernard")).findFirst(); name.map(x -> x.toUpperCase()). ifPresent(x -> System.out.println(x)); System.out.println("Done"); } }
  • 33.
    Collectors ● Implementation ofthe Collector interface. ● Performs useful reduction operations on stream, e.g., – Accumulation of elements into collections, – Summarising values, – Grouping, – Partitioning ● Typically used in the collect method of the stream to return the final collection after the stream pipeline has executed.
  • 34.
    Collectors - Example /** *Return a list of even numbers from a list of string * representation of integers. * @param args */ List<String> numStr = Arrays.asList("53", "26", "33", "77", "2", "8", "9", "98"); List<Integer> evenNums = numStr.stream(). map(x -> Integer.parseInt(x)). filter(x -> x % 2 == 0). collect(Collectors.toList()); evenNums.forEach(System.out::println);
  • 35.
    Stream Reduction -Example List<Double> nums = Arrays.asList(25.5, 23.25, 17.0, 9.25); /* * reduce takes an initial accumulator value and a BiFunction * extension that takes the accumulated value, iteratively adds * the elements in the stream. */ double average = nums.stream(). reduce(0.0, (acc, x) -> acc + x)/nums.size(); System.out.printf("Average = %.3f", average);
  • 36.
    Collector Reduction -Example List<Double> nums = Arrays.asList(25.5, 23.25, 17.0, 9.25); double average = nums.stream(). collect(Collectors.averagingDouble(x -> x)); System.out.printf("Average = %.3f", average);
  • 37.
    Creating Streams ● static Stream<T> of(T... values) –Creates a stream of values specified. ● static  IntStream range(int inclusiveStart,  int exclusiveEnd) – Sequentially ordered stream of integers with increment of 1 excluding the end value. ● static IntStream rangeClosed(int  inclusiveStart, int inclusiveEnd) – Sequentially ordered stream of integers with increment of 1 including the end value.
  • 38.
    IntStream - Example IntStreamrange = IntStream.rangeClosed(1, num); int factorial = range.reduce(1, (acc, x) -> acc * x); System.out.printf("%d! = %dn", num, factorial);
  • 39.
  • 40.
    flatMap ● Consider acollection of collections of items. – flatMap used to transform items of inner collections. – and then flatten the collection of collections of transformed items to a collection of transformed items. ● Defined for – Stream, – Optional
  • 41.
    Example – StreamflatMap List<List<String>> linesOfWords = Arrays.asList(Arrays.asList("Incy", "wincy", "spider"), Arrays.asList("Climbing", "up", "the", "spout")); Stream<String> dataStream = linesOfWords.stream(). flatMap(line -> line.stream().map(word -> word.toUpperCase())); List<String> data = dataStream.collect(Collectors.toList()); data.forEach(System.out::println); INCY WINCY SPIDER CLIMBING UP THE SPOUT
  • 42.
    Example – FlatteningOptional Collections List<Optional<Integer>> nums = Arrays.asList(Optional.of(3), Optional.of(5), Optional.empty(), Optional.of(9)); System.out.println(nums); List<Integer> filteredNums = nums.stream(). filter(n -> n.isPresent()). map(n -> n.get()). collect(Collectors.toList()); System.out.println(filteredNums); [Optional[3], Optional[5], Optional. empty, Optional[9]] [3, 5, 9]