Lambda Expressions and Functional Style Programming - Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Lesson 13. Lambda Expressions and Functional Style Programming

Presenting materials of this chapter is somewhat challenging. From the beginning of this book you’ve gotten to know that Java is an object-oriented language (as opposed to a functional language). You’ve learned that to start any program you’ll need to define classes with attributes and methods, instantiate them as objects, and invoke methods (think functions) on these instances. If a method is declared as static, you can invoke it without the need to instantiate a class, but still you were defining the class first and then a static method inside of it. For example, to process a click on a Swing JButton, you would need to implement and instantiate a listener class containing just one method actionPerformed().

Now I need to tell you that the object-oriented approach may have some drawbacks, and there is a large group of functional programming languages in which you don’t need to wrap functionality inside classes. Proponents of functional languages say (and rightly so) that creating objects with fields that can be changed (mutated) by the methods’ code may be error prone and more difficult to debug. They prefer thinking in terms of functions that don’t depend on the external context.

A function takes the values from the outside world in the form of arguments, apply some application logic and returns the result. A function doesn’t change any external values (including those that were provided as arguments). A function can take a single value (or a data collection) and produce another value, but doesn’t modify the input. So no matter how many times you’ll be invoking any given function with the same input, the returned value will be the same.

In languages such as Haskell, JavaScript, Scala, Closure, and Ruby, functions are treated as first-class citizens, and they don’t require you to write and instantiate classes. In functional languages, you can do the following:

· Assign a function to a variable.

· Pass a function as an argument to another function.

· Define a function inside another function.

· Return a function from another function.

For example, this is how you can create a function that returns another function, in JavaScript:

function () {

var taxDeduction = 500;

return function (income) {

// Implement calculating tax using taxDeduction here

// ...

return calculatedTax;

}

}

Java 8 introduced lambda expressions (from Lambda Calculus), which are anonymous functions. Since the lambda expression has no name, it can be assigned as a value to a named variable.

With lambda expressions, object-oriented Java (as well as C#) allows programing in a mixed style. When you need an object with state, declare a class and instantiate it. If you just need to implement some algorithm define a lambda expression.

In this lesson you find out how to make your Java code more concise with lambda expressions. Java 8 blends functional into object-oriented style by representing a Function as a an object in the Java type system. Also, the interfaces that declare just one abstract method (functional interfaces) now can be implemented without the need to create an object just to contain this method.

Imperative vs Functional Style

Java is not a functional programming language, but even without lambda expressions it allows writing programs with elements of functional style. I’ll show you a quick example illustrating the concept of imperative vs functional styles of programming. The following classImperativeVsFunctional creates a collection winners and populates it with names. Then it tries to find if this collection contains the winner named “Ringo” using two different styles - imperative and then functional.

public class ImperativeVsFunctional {

public static void main(String[] args) {

List<String> winners = new ArrayList<>();

winners.add("Mary");

winners.add("Ringo");

winners.add("Joe");

winners.add("Paul");

// Imperative style

boolean gotRingo = false;

for (String winner: winners){

if ("Ringo".equals(winner)){

gotRingo = true;

System.out.println("Imperative style. Ringo won?"

+ gotRingo);

break;

}

}

// Functional style

System.out.println("Functional style. Ringo won?"

+ winners.contains("Ringo"));

}

}

Running this program will produce the following output:

Imperative style. Ringo won? true

Functional style. Ringo won? true

In imperative style the program dictates what has to be done: create a flag, then in a for-loop check the value of each element and if Ringo is found, change the value of the flag to true and break out of the loop. In this case we assume that ArrayList is just a storage of the winner’s names.

In functional style, we don’t dictate how to search for Ringo, and just call the method contains(). No external loops, no mutable flags, a no breaks. It’s short, concise, and easy to understand. How the method contains() is implemented in the current version of Java? It’s an internal business of the ArrayList. It very well can be that either in this or in the future version of Java the method contains() will split the collection (especially the large one) into smaller chunks and will do a parallel search for Ringo if the computer has multiple processors, while the imperative version will always process this collection sequentially.

This example uses a function that already exists in the collection. But with lambda expressions you can define your own functions and give it for the execution to a class or a collection. And again, depending on what your lambda does, the Java run time may decide to execute it in parallel.

You’ll see some examples comparing imperative and functional styles of programming in the section "Iterating Collections with foreach" later in this chapter. With imperative style we tell Java how to do things, but with functional we tell Java what we want to do. In Lesson 20 on Stream API you’ll see more examples of writing code in declarative and functional style. Let’s learn the syntax of the lambda expressions now.

What’s Lambda Expression

A lambda expression is an anonymous function that you can

· Assign to a variable.

· Pass as an argument to another function.

· Return from a method.

If in earlier versions of Java only objects and primitives could represent values, as of Java 8, functions can be values as well. In Lesson 9 you learned about anonymous inner classes served as wrapper for methods. Lambda expressions can eliminate the need for such wrappers. For example, consider the following lambda expression (let’s call them lambdas for brevity):

(int a, int b) -> a + b;

Assume that there is an interface that declares a single abstract method that takes two int arguments and returns an int value. The lambda in the preceding code is an anonymous function that takes two int arguments a and b. The arguments are placed inside the parentheses similarly to Java methods. Actually, if lambda expression has only one argument then even those parentheses are not needed. On the right side of the -> sign (a.k.a. arrow token) you see the body of the lambda expression. In this case it’s just a one-liner that calculates and returns the sum of arguments. If the body of lambda is a single-line expression as in the preceding example, there is no need to write a return statement. The result of the lambda expression is returned implicitly.

While the syntax of a lambda expression may look unusual, it’s pretty easy to understand. Just take a regular Java method declaration, remove everything to the left of the opening paren, and add the -> sign after the closing paren. So if you wanted to rewrite the above lambda expression as a Java method, it could look like this:

public int addNumbers(int a, int b){

return a + b;

}

image

Figure 13-1: Parts of a lambda expression

In lambda expressions, specifying argument types is optional. Lambdas support inferred data types; the Java compiler properly “guesses” the types based on the context of your code. So our lambda expression can be rewritten as follows:

(a, b) -> a + b;

If the lambda expression consists of several lines of code, you need to put the code inside the curly braces and add an explicit return statement. You can pass lambda expressions to a method to be applied there. You’ll see the example of using apply() in the section titled "Interfaces Function and BiFunction.” The Java 8 lambdas can represent single-method interfaces in a concise way, which is discussed next.

Functional Interfaces

A Java interface can declare any number of methods, but to be implemented as lambdas, the interface has to declare a single non-implemented method. Such interfaces are called functional interfaces. Technically, functional interfaces can have more than one method; some of them can be static, some of them can be implemented as default methods—these don’t count. The important part is that there is only one abstract method that has to be implemented.

Consider the ActionListener interface that you used in Lesson 9 to process button clicks:

public interface ActionListener extends EventListener {

public void actionPerformed(ActionEvent actionEvent);

}

The old way of implementing such an interface with an anonymous inner class could look like this:

myButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent actionEvent) {

someTextField.setText("Someone clicked on the button");

}

});

Because ActionListener defines a single method actionPerformed() it can be called functional interface. Hence it can be represented in a concise form with a lambda expression:

myButton.addActionListener(actionEvent -> {

someTextField.setText("Someone clicked on the button);

});

It is a lot simpler to write and read, isn’t it? No need to declare and instantiate anonymous classes. This lambda expression has one argument represented by the variable actionEvent (you could name it anything and no data type is needed). The method actionPerformed() is a callback, and Java run time would pass the instance of ActionEvent to it. But because it is a single method interface, the compiler is smart enough to figure out the type of the argument so you don’t even need to declare it. Because any functional interface has a single method, it is easy for the compiler to figure out its name, so you just can write a lambda expression as its implementation.

Method References

In some cases your lambda expression just calls a predefined method. Java 8 introduces method references that can be used instead of lambda expressions. The new syntax introduces a double colon operator ::, and you can write something like this:

myObject::myMethod

There is no parentheses after the method name and you can’t specify the arguments in method references. So this syntax applies to the cases when either the method has no arguments or the compiler can “figure out” what such method expects as an argument. For example, the following method has no arguments and can be invoked using method reference syntax:

public void myMethod(){

System.out.println("Hello from myMethod");

}

The case with inferred arguments, which the compiler figures out, can be illustrated by the event listener callback methods. The following class MethodReferenceSample uses method reference syntax in addActionListener(). The compiler figures out that the processButtonClick() method expects the argument of the type ActionEvent.

public class MethodReferenceSample extends JFrame {

public void processButtonClick(ActionEvent actionEvent){

System.out.println("Someone clicked on the button");

}

public static void main(String args[]){

MethodReferenceSample mrs = new MethodReferenceSample();

JButton myButton = new JButton("Click me");

mrs.add(myButton);

myButton.addActionListener(mrs::processButtonClick);

mrs.pack();

mrs.setVisible(true);

mrs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

}

Eclipse Luna and Lambdas

Eclipse Luna (as well as NetBeans and IntelliJ IDEA) offers help in converting anonymous inner classes that implement functional interfaces into lambda expressions. Highlight the anonymous class creation (starting with new), and select the Quick Fix option by pressing Ctrl+1 ( or Cmd+1 on Mac). Eclipse opens a menu. Select the Convert to Lamba Expression option to turn the anonymous inner class into a lambda expression.

Annotation @FunctionalInterface

In Lesson 23 you’ll be learning about Java annotations, which are metadata about Java code. Some annotation affect the process of compilation while other instruct Java run time to do certain things with the code. Java 8 introduces a new annotation that you can use for explicitly marking your interfaces as functional like this:

@FunctionalInterface

public interface Payable {

boolean increasePay(int percent);

}

Using the annotation @FunctionalInterface is optional. It just shows your intention to implement this interface as a lambda expression. People who read your code may appreciate this hint. In the section "Passing Functions to Methods" I’ll show you an example of using this annotation.

Methods Versus Functions

The difference between methods and functions is that functions are not attached to any class instance. You can say that static methods are also not attached to the instances, but static methods have to be declared inside a class or an interface, whereas functions don’t.

You can try using lambdas just to simplify your code in places where you need to implement functional interfaces while maintaining an object-oriented style of programming. The code sample of replacing anonymous an inner class implementing ActionListener is an illustration of such simplification.

On the other hand, you may start experimenting with a functional style of programming, where a function just gets some input, applies its business logic, and returns the results. A function doesn’t know anything about the context it operates in unless it was given to it as an argument. A function doesn’t belong to any object hence it cannot rely on the fact that certain external values can be used in performing its action. A function does not change the state of any object.

The following example of the class Tax is written in object-oriented style. After the object of type Tax is instantiated, its fields grossIncome and the method calcTax() are not functions, as it expects to get some values from class variable grossIncome that modifies federalTax. It’s a situation with mutable state.

class Tax{

double grossIncome;

double federalTax;

public void calcTax() {

if (grossIncome < 30000) {

federalTax=grossIncome*0.05;

}

else{

federalTax= grossIncome*0.06;

}

}

}

In the object-oriented world it’s perfectly fine, because an object is the center of the universe there. To eliminate mutable attributes (grossIncome and federalTtate), change the definition of this class to:

class TaxNoState{

public static double calcTax(double grossIncome) {

double federalTax=0;

if (grossIncome < 30000) {

federalTax=grossIncome*0.05;

}

else{

federalTax= grossIncome*0.06;

}

return federalTax;

}

}

in TaxNoState the method calculateStateTax() gets the required values via its arguments. It’s still a method since it lives inside the class, but is closer to being a function. After applying business logic calculateStateTax() returns the calculated federalTax. Returns to whom? It’s none of the function’s business. Note that I’ve used the keyword static in the method declaration to remove any attachments to specific instances of the class TaxNoState. After all, the tax calculation should be done the same way for Mary and Joe if they have the same income.

In the class TaxNoState we removed class variables and used the method arguments instead. The question is why the tax calculation logic that doesn’t use any class fields have to live inside class method? Can you provide the code to calculate the tax from outside? Prior to Java 8, primitives or objects were the only values that you could pass to a method. But now you can also pass lambda expressions as method arguments, and I’ll give you an example of this in the next section.

Passing Functions to Methods

In functional programming, you can pass a function as an argument to another function (or a function can return a function). Such outer functions are called higher-order functions.

This section shows you how to pass a function to a Java method. We’ll create a class with three fields: name, grossIncome, and state to represent a customer of some accounting office. This class will have a method applyTaxCalculationFunction(), but the code of this function will be provided to this method as an argument. Here’s the code of the class Customer:

public class Customer{

public String name;

public double grossIncome;

public void applyTaxCalcFunction(TaxFunction taxFunc) {

double calculatedTax = taxFunc.calcTax(grossIncome);

System.out.println( "The calculated tax for " + name +

" is "+ calculatedTax );

}

}

The argument of the method applyTaxCalcFunction() is an implementation of the functional interface TaxFunction, which is shown here:

@FunctionalInterface

public interface TaxFunction {

double calcTax(double grossIncome);

}

The implementation of this interface is provided by lambda expressions defined in the class TestTaxLambda. This class creates two customer instances and invokes the method applyTaxCalculationFunction() providing the lambda to execute. The customer’s methodapplyTaxCalculationFunction() receives the implementation of this interface and invokes its method calcTax(). Here’s the code of the class TestTaxLambda:

public class TestTaxLambda {

public static void main(String[] args) {

// Define one function as a lambda expression

// and store it in a variable

TaxFunction taxFunction = (double grossIncome) -> {

double federalTax=0;

if (grossIncome < 30000) {

federalTax=grossIncome*0.05;

}

else{

federalTax= grossIncome*0.06;

}

return federalTax;

};

// Define another function as a lambda expression

// for calculating tax for mafia members

TaxFunction taxFunctionMafia = (double grossIncome) -> {

double stateTax=0;

if (grossIncome < 30000) {

stateTax=grossIncome*0.01;

}

else{

stateTax= grossIncome*0.02;

}

return stateTax;

};

Customer customer1 = new Customer();

customer1.name = "Mary Lou";

customer1.grossIncome=50000;

customer1.applyTaxCalcFunction(taxFunction);

Customer customer2 = new Customer();

customer2.name = "Al Capone";

customer2.grossIncome=25000;

customer2.applyTaxCalcFunction(taxFunctionMafia);

}

}

The implementation of two different algorithms of tax calculation is stored in lambda expressions is stored in the variable taxFunction and taxFunctionMafia. If you run TestTaxLambda, you see the following output on the console:

The calculated tax for Mary Lou is 3000.0

The calculated tax for Al Capone is 250.0

Lambda expressions spare you from needing to wrap a function inside a class. The big question is what’s better: providing the tax calculation function inside the class Customer or passing it from outside. There is no general answer for this. Just know that if the business rules of your application require you to apply a the same or different pieces of a functionality to different objects, lambda expressions allow you to do this.

Java 8 lambdas still have some restrictions, and you can pass it to a method that expects a lambda that implements an interface of a specified type (TaxFunction in this case). In functional languages like JavaScript, you can attach an arbitrary function to any object and execute in the context of that object with functions call() or apply(). You see the Java version of apply() in the last section of this lesson.

Iterating Collections with forEach()

In the previous lesson you iterated a collection of objects by writing a loop. To perform some actions on each object of a collection you can implement these actions in the method doSomething() that’s called in the loop body:

List<Customer> customers = new ArrayList<>();

// The code to populate customers is omitted for brevity

// Iterate through the list customers and do something with each

// element of this collection.

for (Customer customer : customers){

customer.doSomething();

}

This is an imperative way of programming, you say, “I want get every element of the collection sequentially and do something with it." But there is a functional approach to this task, “Hey, collection, I’ll give you a function to perform on each of your elements. Please figure out the best way to do it."

You may say, “What do you mean by the best way? Does collection know better than me how to process its elements?” Yes, it does. Starting with Java 8, collection became smarter and can parallelize execution, especially on multiprocessor computers. For example, it may internally split the collection in half and apply doSomething() in parallel for each half, and then it merges the results back. So you’d better give your function to a collection; there is a chance the processing will finish faster.

I’ll show you the implementation of both imperative and functional styles in the class TestCollectionsForEach below. It’ll iterate through the collection of workers represented by the instances of the class Person, which has a boolean variable workerStatus to store the employment : E means employee, and C means contractor.

public class Person {

private String name;

private char workerStatus; // 'E' or 'C'

public Person (String name, char workerStatus){

this.name = name;

this.workerStatus = workerStatus;

}

public String getName() {

return name;

}

public char getWorkerStatus() {

return workerStatus;

}

}

The program TestCollectionsForEach creates an array of Person instances and then turns it into a List with Arrays.asList(). After that it iterates through the list using two different techniques: imperative and functional.

public class TestCollectionsForEach {

public static void main(String[] args) {

Person workers[] = new Person[3];

workers[0] = new Person("John", 'E');

workers[1] = new Person("Mary", 'C');

workers[2] = new Person("Steve", 'E');

List<Person> workersList = Arrays.asList(workers);

// Imperative loop

System.out.println("1. Running imperative loop");

for (Person person : workersList){

if ('E' == person.getWorkerStatus()){

System.out.println(person.getName() + " is employee");

} else if ('C' == person.getWorkerStatus()){

System.out.println(person.getName() + " is contractor");

}

}

// Functional loop

System.out.println("2. Running functional loop");

workersList.forEach(person -> {

if ('E' == person.getWorkerStatus()) {

System.out.println(person.getName() + " is employee");

} else if ('C'==pers.getWorkerStatus()){

System.out.println(person.getName() + " is contractor");

}

});

}

}

The output of this program is shown here:

1. Running imperative loop

John is employee

Mary is contractor

Steve is employee

2. Running functional loop

John is employee

Mary is contractor

Steve is employee

The output is the same from both loops. In the functional loop you’re passing a lambda expression to the forEach() method of the collection.

In Lesson 20 you learn about the new Stream API, and you see there how to specifically request parallel processing.

I’d like to bring your attention to the variable person in the argument to the forEach() method. I’ve never declared this variable, so what its type? It’s yet another example of the type inference. Java is smart enough to see that the lambda expression is being applied to the collection of the classPerson (see, generics are helpful!). Hence the variable person will be typed as Person. You can name this variable anything you want; the Java compiler will figure out its inferred type.

Lambdas Versus Inheritance and Polymorphism

Lambda expressions promote a functional style of programming. In previous lessons you’ve learned about the object-oriented style and its major concepts: inheritance, which can be implemented as polymorphism or composition. This section shows you how to take the example from the section "Making the Interface Solution Polymorphic" from Lesson 7 where you processed a collection of employees and contractors in polymorphic ways and rewrite it using composition with lambdas.

Inheritance vs Composition

To create a class that can reuse features of another class you can use either inheritance or composition as a design technique. In case of inheritance you can simply create a ClassB that extends ClassA and use the ancestor’s elements from a descendent class. The following example demonstrates inheritance, where the ClassB invokes in constructor a method doSomething() declared in its ancestor:

ClassA {

public void doSomething(){

}

}

ClassB extends ClassA{

ClassB(){

doSomething();

}

}

In case of composition, you don’t need to inherit from ClassA, but just instantiate (and hold a reference) ClassA in ClassB:

ClassA {

public void doSomething(){

}

}

ClassB{

ClassB(){

ClassA classA = new classA();

classA.doSomething();

}

}

For pros and cons of inheritance vs composition, read the JavaWorld article "Inheritance versus Composition: Which one Should You Choose?"

In that Lesson 7 example you used the Payable interface to increase pay for employees and contractors. First, refresh your memory about that application. Figure 13-2 shows the class diagram of that application (in UML notation arrows mean extends, and dashed arrows means implements):

image

Figure 13-2: Figure 13-2. Extending Person and implementing Payable

The code of the superclass Person is shown next:

public class Person {

private String name;

public Person(String name){

this.name = name;

}

public String getName(){

return "Person's name is " + name;

}

}

This is the Payable interface:

public interface Payable {

int INCREASE_CAP = 20;

boolean increasePay(int percent);

}

Classes Employee and Contractor had different implementations of the Payable interface. This is what Employee looked like:

public class Employee extends Person implements Payable {

public Employee(String name){

super(name);

}

public boolean increasePay(int percent) {

System.out.println("Increasing salary by " + percent + "%. "+

getName());

return true;

}

}

The class Contractor looked as follows:

public class Contractor extends Person implements Payable {

public Contractor(String name){

super(name);

}

public boolean increasePay(int percent) {

if(percent < Payable.INCREASE_CAP){

System.out.println("Increasing hourly rate by " +

percent + "%. "+ getName());

return true;

} else {

System.out.println(

"Sorry, can't increase hourly rate by more than " +

Payable.INCREASE_CAP + "%. "+ getName());

return false;

}

}

}

The program TestPayIncreasePoly demonstrated the polymorphic behavior of Employee and Contractor objects.

public class TestPayInceasePoly {

public static void main(String[] args) {

Payable workers[] = new Payable[3];

workers[0] = new Employee("John");

workers[1] = new Contractor("Mary");

workers[2] = new Employee("Steve");

for (Payable p: workers){

p.increasePay(30);

}

}

}

Eliminating Inheritance

The only difference between Contractor and Employee was the implementation of the increasePay() method, extracting the implementation of this method into a lambda expression. This enables you to get rid of the classes Employee and Contractor and simply pass the proper function to the class Person. To be able to distinguish contractors and employees you use the version of the class Person from the section “Iterating collection with forEach() Method.” But this time add a method validatePayIncrease() that takes the lambda expression as one parameter and the amount of pay increase as another. This is the new version of the class Person:

public class Person {

private String name;

private char workerStatus; // 'E' or 'C'

public Person (String name, char workerStatus){

this.name = name;

this.workerStatus = workerStatus;

}

public String getName(){

return name;

}

public char getWorkerStatus(){

return workerStatus;

}

public boolean validatePayIncrease(Payable increaseFunction,

int percent) {

boolean isIncreaseValid =

increaseFunction.increasePay(percent);

System.out.println( " Increasing pay for " + name +

" is " + (isIncreaseValid? "valid.": "not valid."));

return isIncreaseValid;

}

}

The Payable interface remains the same, and its implementation will be represented by two lambda expressions—one for employees and another one for contractors, as shown in the program TestPayIncreaseLambda:

public class TestPayIncreaseLambda {

public static void main(String[] args) {

Person workers[] = new Person[3];

workers[0] = new Person("John", 'E');

workers[1] = new Person("Mary", 'C');

workers[2] = new Person("Steve", 'E');

// Lambda expression for increasing Employee's pay

Payable increaseRulesEmployee = (int percent) -> {

return true;

};

// Lambda expression for increasing Contractor's pay

Payable increaseRulesContractor = (int percent) -> {

if(percent > Payable.INCREASE_CAP){

System.out.print(

" Sorry, can't increase hourly rate by more than " +

Payable.INCREASE_CAP + "%. ");

return false;

} else {

return true;

}

};

for (Person p: workers){

if ('E'==p.getWorkerStatus()){

// Validate 30% increase for every worker

p.validatePayIncrease(increaseRulesEmployee, 30);

} else if ('C'==p.getWorkerStatus()){

p.validatePayIncrease(increaseRulesContractor, 30);

}

}

}

}

Running this program produces the same output as the version with class inheritance and polymorphism:

Increasing pay for John is valid.

Sorry, can't increase hourly rate by more than 20%.

Increasing pay for Mary is not valid.

Increasing pay for Steve is valid.

The result is the same, so what have you achieved? Using lambdas made it possible to remove two classes: Contractor and Employee. This is good. But it seems that by removing these classes you’ve lost the strict contract enforcement to implement the Payable interface. Actually, though, you didn’t! Using the Payable type is still enforced but in a different way; now it’s a type of the argument in the method validatePayIncrease(). If a new type of a worker will be introduced (for example, foreign workers), you just need to add another lambda expression to the classTestPayIncreaseLambda that implements business rules for foreign workers.

Closures with Lambdas

The “Closures in Java” section in Lesson 17 demonstrates an important concept of functional programming: closures.

Interfaces Function and BiFunction

On the other hand, even the interface Payable can be eliminated from the increase pay example. Revisit the class Person from the section “Eliminating Inheritance.” It has a method validatePayIncrease where the first argument is strictly typed as Payable. But Java 8 allows passing any arbitrary function to a method as an argument. There is a new package java.util.function that has a number of useful interfaces for those who like functional programming. For example, the interface Function has the following declaration:

@FunctionalInterface

public interface Function<T, R>

As you see, it uses generics. This interface has two parameters: T for type and R for the type of the return value of the method apply() declared in the interface Function. Using T for type and R for the type of the return value became idiomatic in Java, so you should also use these letters in your code. You can pass the code of such a function to a class method and apply this function to a provided argument.

The interface BiFunction declares two arguments (T and U) and a return value (R):

@FunctionalInterface

public interface BiFunction<T, U, R>

Accordingly, the BiFunction interface declares a method R apply(T, U). Let’s see if you can use it in the increase pay example, which is built using the techniques you’ve learned in this lesson.

First, take a look at the new version of the class Person. Note the change in the arguments of the method validateIncreasePay():

public class Person {

private String name;

private char workerStatus; // 'E' or 'C'

public Person (String name, char workerStatus){

this.name = name;

this.workerStatus=workerStatus;

}

public String getName(){

return name;

}

public char getWorkerStatus(){

return workerStatus;

}

public boolean validateIncreasePay(

BiFunction<Person, Integer, Boolean> func

, int percent) {

boolean isIncreaseValid = func.apply(this, percent);

System.out.println( " Increasing pay is " +

(isIncreaseValid? "valid.": "not valid."));

return isIncreaseValid;

}

}

The method validateIncreasePay() has two arguments: a BiFunction for the function to apply and a proposed increase pay percent to validate. In turn, BiFunction declares two arguments—one of type Person and the other of type Integer—and a Boolean return type. When actual implementation of BiFunction is passed to the method validateIncreasePay(), it invokes it using the method apply(). The keyword this represents the current instance of a Person, and percent is the proposed increased amount.

Once again, the term higher order function is a function (or method) that either takes a function as an argument or returns a function. In other words, higher order functions work on other functions.

The program TestPayIncreaseFunctionInterface, which declares the lambdas for contractors and employees and validates a list of workers, is shown here:

public class TestPayIncreaseFunctionInterface{

public static void main(String[] args) {

final int INCREASE_CAP = 20; // cap for pay increase in %

int proposedIncrease = 30; // percent

Person workers[] = new Person[3];

workers[0] = new Person("John", 'E');

workers[1] = new Person("Mary", 'C');

workers[2] = new Person("Steve", 'E');

List<Person> workersList = Arrays.asList(workers);

// Define functions with 2 args Person and percent

// that returns Boolean

// Lambda expression for increasing Employee's pay

BiFunction <Person, Integer, Boolean> increaseRulesEmployee =

(pers,percent) -> {

System.out.print(" Increasing pay for " +

pers.getName() + " is valid");

return true; // allow any increases for employees

};

// Lambda expression for increasing Contractor's pay

BiFunction <Person, Integer, Boolean> increaseRulesContractor =

(pers,percent) -> {

if(percent > INCREASE_CAP){

System.out.print(

" Sorry, can't increase hourly rate by more than " +

INCREASE_CAP + "%. for " + pers.getName());

return false;

} else {

return true;

}

};

// Validate pay increase

workersList.forEach(pers -> {

if ('E'==pers.getWorkerStatus()){

pers.validateIncreasePay(increaseRulesEmployee,

proposedIncrease);

} else if ('C'==pers.getWorkerStatus()){

pers.validateIncreasePay(increaseRulesContractor,

proposedIncrease);

}

});

}

}

In the previous section you stored lambdas in the variables of type Payable, but in this version it’s stored as a BiFunction; for example:

BiFunction <Person, Integer, Boolean> increaseRulesEmployee

The Payable interface is gone. I just moved the final variable INCREASE_CAPin the class TestPayIncreaseFunctionInterface. In the beginning of this lesson we designed the increase pay application using four classes and one interface. Now we have just two classes and the code became shorter.

The goal of this lesson was to explain the concept of lambdas and show some practical use cases where they can simplify your code. I didn’t want to repeat all syntax details of lambdas. Please visit Oracle’s tutorial on lambda expressions (http://goo.gl/xS3ejB) for further studying of this subject.

Try It

The goal of this lesson is to add another lambda expression to the class TestPayIncreaseLambda to process pay increases for foreign workers.

Lesson Requirements

You should have Java installed.

NOTE You can download the code and resources for this “Try It” from the book’s web page at www.wrox.com/go/javaprog24hr2e. You can find them in Lesson13.zip.

Step-by-Step

1. Import into Eclipse the project Lesson13 from the file Lesson13.zip. Review the code of all examples from this lesson.

2. Introduce the new type of workers: a foreign worker.

3. Come up with some business logic for increasing rate for foreigners.

4. Create a new lambda expression implementing these rules and assign it to the variable Payable increaseRulesForeigner.

5. Add an instance of the foreign worker (worker status 'F') to the array workers.

6. Modify the for loop in the class TestPayIncreaseLambda to process pay increase for foreigners.

7. Extra challenge: Modify the class Person to remove the workerStatus attribute. Add a second parameter to its constructor—a lambda expression—so you can pass the rules of increasing pay during instantiation of a worker.

TIP Please select the videos for Lesson 13 online at www.wrox.com/go/javaprog24hr2e. You will also be able to download the code and resources for this lesson from the website.