15 Java 8 Lambda Expressions Part 3
15 Java 8 Lambda Expressions Part 3
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic. λ
Lambda
Building Blocks
in java.util.function
Slides © 2016 Marty Hall, [email protected]
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
Main Points
• java.util.function: many reusable interfaces
– Although they are technically interfaces with ordinary methods, they are treated as
though they were functions
• Simply typed interfaces
– IntPredicate, LongUnaryOperator, DoubleBinaryOperator, etc.
• Generically typed interfaces
– Predicate<T> — T in, boolean out
– Function<T,R> — T in, R out
– Consumer<T> — T in, nothing (void) out
– Supplier<T> — Nothing in, T out
– BinaryOperator<T> — Two T’s in, T out
Simply Typed
Building Blocks
Slides © 2016 Marty Hall, [email protected]
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
Main Points
• Interfaces like Integrable widely used
– So, Java 8 should build in many common cases
• Can be used in wide variety of contexts
– So need more general name than “Integrable”
• java.util.function defines many simple functional (SAM)
interfaces
– Named according to arguments and return values
• E.g., replace my Integrable with builtin DoubleUnaryOperator
– You need to look in API for the method names
• Although the lambdas themselves don’t refer to method names, your code that uses
the lambdas will need to call the methods explicitly
10
11
Interface from Previous Lecture
@FunctionalInterface
public interface Integrable {
double eval(double x);
}
12
13
Method for Testing
public static void integrationTest(Integrable function,
double x1, double x2) {
for(int i=1; i<7; i++) {
int numSlices = (int)Math.pow(10, i);
double result =
MathUtilities.integrate(function, x1, x2, numSlices);
System.out.printf(" For numSlices =%,10d result = %,.8f%n",
numSlices, result);
}
}
14
15
Using Builtin Building Blocks
• In integration example, replace this
public static double integrate(Integrable function, …) {
... function.eval(...); ...
}
• With this
public static double integrate(DoubleUnaryOperator function, …) {
... function.applyAsDouble(...); ...
}
16
General Case
• If you are tempted to create an interface purely to be used as a
target for a lambda
– Look through java.util.function and see if one of the functional (SAM) interfaces
there can be used instead
• DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator
– double/int/long in, same type out
• DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator
– Two doubles/ints/longs in, same type out
• DoublePredicate, IntPredicate, LongPredicate
– double/int/long in, boolean out
• DoubleConsumer, IntConsumer, LongConsumer
– double/int/long in, void return type
• Genericized interfaces: Function, Predicate, Consumer, etc.
– Covered in next section
17
coreservlets.com – custom onsite training
Generic Building
Blocks: Predicate
Slides © 2016 Marty Hall, [email protected]
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
21
Without Predicate: Finding Employee by Salary
public static Employee findEmployeeBySalary(List<Employee> employees,
double salaryCutoff) {
for(Employee e: employees) {
if(e.getSalary() >= salaryCutoff) {
return(e);
}
}
return(null);
}
Most of the code from the previous example is repeated. If we searched by last name or employee ID,
22 we would yet again repeat most of the code.
23
Refactor #1: Benefits
• Now
– We can now pass in different match functions to search on different criteria.
Succinct and readable.
• firstMatchingEmployee(employees, e -> e.getSalary() > 500_000);
• firstMatchingEmployee(employees, e -> e.getLastName().equals("…"));
• firstMatchingEmployee(employees, e -> e.getId() < 10);
• Before
– Cumbersome interface.
• Without lambdas, we could have defined an interface with a “test” method, then
instantiated the interface and passed it in, to avoid some of the previously repeated
code. But, this approach would be so verbose that it wouldn’t seem worth it in most
cases. The method calls above, in contrast, are succinct and readable.
• Doing even better
– The code is still tied to the Employee class, so we can do even better (next slide).
24
We can now pass in different match functions to search on different criteria as before,
but can do so for any type, not just for Employees.
25
Using firstMatch
• firstMatchingEmployee examples still work
– firstMatch(employees, e -> e.getSalary() > 500_000);
– firstMatch(employees, e -> e.getLastName().equals("…"));
– firstMatch(employees, e -> e.getId() < 10);
• But more general code now also works
– Country firstBigCountry =
firstMatch(countries, c -> c.getPopulation() > 10_000_000);
– Car firstCheapCar =
firstMatch(cars, c -> c.getPrice() < 15_000);
– Company firstSmallCompany =
firstMatch(companies, c -> c.numEmployees() <= 50);
– String firstShortString =
firstMatch(strings, s -> s.length() < 4);
26
@Test
public void testNames() {
assertThat(findEmployeeByFirstName(EMPLOYEES, FIRST_NAMES[0]),
is(notNullValue()));
for(String firstName: FIRST_NAMES) {
Employee match1 =
findEmployeeByFirstName(EMPLOYEES, firstName);
Employee match2 =
firstMatchingEmployee(EMPLOYEES, e -> e.getFirstName().equals(firstName));
Employee match3 =
firstMatch(EMPLOYEES, e -> e.getFirstName().equals(firstName));
assertThat(match1, allOf(equalTo(match2), equalTo(match3)));
} Testing goals:
• The hardcoded version gives same answer as the version with the Predicate<Employee>, but not merely by both always returning null.
}
27
• The version with generic types gives same answer and has identical syntax (except for method name) as the version with Predicate<Employee>.
Reminder: JUnit covered in earlier section.
Testing Lookup by Salary
private static final List<Employee> EMPLOYEES = EmployeeSamples.getSampleEmployees();
private static final int[] SALARY_CUTOFFS = { 200_000, 300_000, 400_000 };
@Test
public void testSalaries() {
assertThat(findEmployeeBySalary(EMPLOYEES, SALARY_CUTOFFS[0]),
is(notNullValue()));
for(int cutoff: SALARY_CUTOFFS) {
Employee match1 =
findEmployeeBySalary(EMPLOYEES, cutoff);
Employee match2 =
firstMatchingEmployee(EMPLOYEES, e -> e.getSalary() >= cutoff);
Employee match3 =
firstMatch(EMPLOYEES, e -> e.getSalary() >= cutoff);
assertThat(match1, allOf(equalTo(match2), equalTo(match3)));
}
}
28
Except for @FunctionalInterface, this is the same way you could have
written Predicate in Java 7. But, it wouldn't have been very useful in Java 7
because the code that supplied the Predicate would have to use a clumsy
and verbose inner class instead of a lambda.
And, I am oversimplifying this definition, because Predicate has some default and static methods. But, they
wouldn’t be needed for the use of Predicate on previous slides.
29
General Lambda Principles Revisited
• Interfaces in Java 8 are same as in Java 7
– Predicate is same in Java 8 as it would have been in Java 7, except you can (and
should!) optionally use @FunctionalInterface
• To catch errors (multiple methods) at compile time
• To express design intent (developers should use lambdas)
• Code that uses interfaces is the same in Java 8 as in Java 7
– I.e., the definition of firstMatch is exactly the same as you would have written it in
Java 7. The author of firstMatch must know that the real method name is test.
• Code that calls methods that expect 1-method interfaces can
now use lambdas
– firstMatch(employees, e -> e.getSalary() > 500_000);
30
Generic Building
Blocks: Function
Slides © 2016 Marty Hall, [email protected]
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
Function: Main Points
• Simplified definition
public interface Function<T,R> {
R apply(T t);
}
• Idea
– Lets you make a “function” that takes in a T and returns an R
• BiFunction is similar, but “apply” takes two arguments
• Benefit
– Lets you transform a value or collection of values, with much less repeated code
than without lambdas
• Syntax example
Function<Employee, Double> raise = e -> e.getSalary() * 1.1;
for(Employee employee: employees) {
employee.setSalary(raise.apply(employee));
32 }
33
Previous Section: Transforming with
StringFunction
• Our interface
@FunctionalInterface
public interface StringFunction {
String applyFunction(String s);
}
• Our method
public static String transform(String s, StringFunction f) {
return(f.applyFunction(s));
}
• Sample usage
String result = Utils.transform(someString, String::toUpperCase);
34
35
Refactor 2: Generalize the Types
• Our interface
– None
• Our method
public static <T,R> R transform(T value, Function<T,R> f) {
return(f.apply(value));
}
• Sample usage (more general)
String result = Utils.transform(someString, String::toUpperCase);
List<String> words = Arrays.asList("hi", "bye");
int size = Utils.transform(words, List::size);
36
37
Without Function: Finding Sum of Employee
Salaries
public static int salarySum(List<Employee> employees) {
int sum = 0;
for(Employee employee: employees) {
sum += employee.getSalary();
}
return(sum);
}
38
39
With Function: Finding Sum of Arbitrary Property
public static <T> int mapSum(List<T> entries,
Function<T, Integer> mapper) {
int sum = 0;
for(T entry: entries) {
sum += mapper.apply(entry);
}
return(sum);
}
40
Results
• You can reproduce the results of salarySum
– int numEmployees = mapSum(employees, Employee::getSalary);
• You can also do many other types of sums:
– int totalWeight = mapSum(packages, Package::getWeight);
– int totalFleetPrice = mapSum(cars, Car::getStickerPrice);
– int regionPopulation = mapSum(countries, Country::getPopulation);
– int regionElderlyPopulation =
mapSum(listOfCountries,
c -> c.getPopulation() – c.getPopulationUnderSixty());
– int sumOfNumbers = mapSum(listOfIntegers, Function.identity());
41
coreservlets.com – custom onsite training
Other Generic
Building Blocks
Slides © 2016 Marty Hall, [email protected]
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
• More details
– See later lecture on Streams
46
Wrap-Up
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.
Summary
• Type-specific building blocks
– BlahUnaryOperator, BlahBinaryOperator, BlahPredicate, BlahConsumer
• Generic building blocks
– Predicate
Predicate<Employee> matcher = e -> e.getSalary() > 50000;
if(matchFunction.test(someEmployee)) { doSomethingWith(someEmployee); }
– Function
Function<Employee, Double> raise = e -> e.getSalary() + 1000;
for(Employee employee: employees) { employee.setSalary(raise.apply(employee)); }
– BinaryOperator
BinaryOperator<Integer> adder = (n1, n2) -> n1 + n2;
int sum = adder.apply(num1, num2);
– Consumer
Consumer<Employee> raise = e -> e.setSalary(e.getSalary() * 1.1);
52 for(Employee employee: employees) { raise.accept(employee); }
Questions?
More info:
http://courses.coreservlets.com/Course-Materials/java.html – General Java programming tutorial
http://www.coreservlets.com/java-8-tutorial/ – Java 8 tutorial
http://courses.coreservlets.com/java-training.html – Customized Java training courses, at public venues or onsite at your organization
http://coreservlets.com/ – JSF 2, PrimeFaces, Java 7 or 8, Ajax, jQuery, Hadoop, RESTful Web Services, Android, HTML5, Spring, Hibernate, Servlets, JSP, GWT, and other Java EE training
Many additional free tutorials at coreservlets.com (JSF, Android, Ajax, Hadoop, and lots more)
For additional materials, please see http://www.coreservlets.com/. The Java tutorial section contains
complete source code for all examples in this tutorial series, plus exercises and exercise solutions for each topic.