Testing java 1.8 : I Love functional programming. "Test lambda expression using collections streams".
Lambda is the most powerfull feature added to java language. Now functions are objects so you can send a function param to a method. This was very commont in other programming languages, and now it is available with a lot changues in apis like collections. Let me show you how easy it is to use this pretty new feature.
-
Filter a collection with lambda expression using boolean predicate Test Class Method and Implementation Class method
-
flightCollection.stream().filter( vuelo -> vuelo.getDate().equals((date)));
-
Reuse predicates with and or and not logical operator Test Class Method and Implementation Class method
-
Stream<Flight> filter = flightCollection.stream().filter( fullFlightPredicate().and(isDatetPredicate(date)));
-
Use any and all operator to streams (boolean operation) Test Class Method and Implementation Class method
-
fullFlightPredicate().and(isDatetPredicate(date))); flightCollection.stream().allMatch( fullFlightPredicate().and(isDatetPredicate(date))); ```
-
Use max and min comparator with stream and testing new optional object, null pointer has death Test Class Method and Implementation Class method
-
.filter(isDatetPredicate(date)) .max(byNumPassengers.thenComparing(byNumSeats));```
-
Created lambda function declaration to be reused (Lambda function, lambda int function)
-
Use mapToInt and Map to double to test sum and average calculation operation Test Class Method and Implementation Class method
-
flightCollection.stream().filter(isDatetPredicate(date)) .mapToInt(getNumPassengers()).sum();
-
OptionalDouble average = flightCollection.stream() .filter(isDatetPredicate(date)).mapToDouble(Flight::getPrice) .average();
-
Added to strings method to Flight and Duration Bean.
-
Added Comparator function to order and calculate max and min value with thenComparing.
-
flightCollection.stream().filter(isDatetPredicate(date)).min(byNumPassengers.thenComparing(byNumSeats));
-
flightCollection.stream().sorted(byNumPassengers.thenComparing(byNumSeats));
-
Added Reduce a flight collection. Reduce operation create an "sum iterate operation for each element". We will calculate sum of all flights using Duration class Test Class Method and Implementation Class method
-
Duration reduceDuration = flightCollection.stream() .map(flight -> flight.getDuration()) .reduce(new Duration(0, 0), (x, y) -> { Integer min = x.getMinutes() + y.getMinutes(); Integer hor = x.getHours() + y.getHours(); return new Duration(hor + min / 60, min % 60); }); return reduceDuration;
-
Added foreach consumer to be able to make change to elements of stream. Example method flightDateAddTenPercentAditionalPrice foreach stream iterate Test Class Method and Implementation Class method
-
flightCollection.stream().forEach(addTenPercentAditionalPrice());
-
Added use collect method to transform our collect to set list or map collection Test Class Method and Implementation Class method
-
List<Duration> flightDateGetListDuration= flightCollection.stream().filter(isDatetPredicate(date)).map(Flight::getDuration).collect(Collectors.toList());
-
Set<Duration> flightDateGetSetDuration=flightCollection.stream().filter(isDatetPredicate(date)).map(Flight::getDuration).collect(Collectors.toSet());
-
Map<String, Duration> flightDateGenerateMapDestionationDuration= flightCollection.stream().filter(isDatetPredicate(date)).collect(Collectors.toMap((Flight flight) -> flight.getDestination(),(Flight flight) ->flight.getDuration()));
-
More information about using map reduction with streams : Map example operation
-
Added use collect method to use groupBy sum and average operation and partition operation Testing new Optional object class on Test Class Method and Implementation Class method
-
Map<Boolean, List<Flight>> flightDateGenerateMapPriceLowCost= flightCollection.stream().filter(isDatetPredicate(date)).collect(Collectors.partitioningBy(flight->flight.getPrice()<=800));
-
Map<Integer, List<Flight>> flightDateGenerateMapGroupByNumSeats= flightCollection.stream().filter(isDatetPredicate(date)).collect(Collectors.groupingBy(flight->flight.getNumSeats()));
-
Map<Integer, Set<Flight>> flightDateGenerateGroupByNumSeatsSet = flightCollection.stream().filter(isDatetPredicate(date)).collect(Collectors.groupingBy(flight->flight.getNumSeats(),Collectors.toSet()))
-
Map<String, Double> flightDateGroupByDestinationAveragePrice=flightCollection.stream().filter(isDatetPredicate(date)).collect(Collectors.groupingBy(flight->flight.getDestination(),Collectors.averagingDouble((Flight flight)->flight.getPrice())));
-
Map<LocalDate, Double> flightGroupByDateSumPrice= flightCollection.stream().collect(Collectors.groupingBy((Flight flight)->flight.getDate(),Collectors.summingDouble((Flight flight)->flight.getPrice())));
Testing java 1.8 : "Dates and optional object"
Dates are new in java 1.8, simmilar to jodatime. A powerfull feature that will let us to forget headache with old calendar´s api. Optional is a new object class that will prevent in our code to throw null pointers exception. Let me show you how easy is to use this new 2 features. (more info at Optional objetc in java 1.8)
- Testing new Optional object class on java 1.8 Test Optional Example method
- OptionalDouble flightDatePriceAverage = flightService.flightDatePriceAverage(flightCollection, date); Assert.assertTrue(flightDatePriceAverage.isPresent());
Optional<String> optional = Optional.of("bam"); Assert.assertTrue(optional.isPresent()); //setting empty value to optional object optional = Optional.empty(); Assert.assertFalse(optional.isPresent());
- Testing new localDate LocalTime and LocalDatetime in java 1.8 Test Dates Example method
Testing @FunctionalInterface and default methods, java 1.8 lambda's magic
Functional Interfaces
How does lambda expressions fit into Javas type system? Each lambda corresponds to a given type, specified by an interface. A so called functional interface must contain exactly one abstract method declaration. Each lambda expression of that type will be matched to this abstract method. Since default methods are not abstract you're free to add default methods to your functional interface.
We can use arbitrary interfaces as lambda expressions as long as the interface only contains one abstract method. To ensure that your interface meet the requirements, you should add the @FunctionalInterface annotation. The compiler is aware of this annotation and throws a compiler error as soon as you try to add a second abstract method declaration to the interface.
Example:
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
- Testing new @FunctionalInterface in java 1.8 and default methods Test @FunctionalInterface
- Another complex example to test funcitional interface with static reference to constructor method (Factory pattern)Create factory pattern with java 1.8
Testing Currying in java 1.8 (functions of multiple parameters)
Currying is the process of transforming a function that takes multiple arguments into a function that takes just a single argument and returns another function if any arguments are still needed. Let's see how to implement this approach in java 1.8:
- Java 1.8 Currying how to Java 1.8 Currying