In my last post, I showed how lambda expressions can improve your code and introduced the Predicate
interface. This post focuses on how the Function
interface can be used in Java.
The java.util.function
Package
Of course, Predicate
is not the only functional interface provided with Java 8. There are a number of standard interfaces designed as a starter set for developers.
Predicate
-- a property of the object passed as argumentConsumer
-- an action to be performed with the object passed as argumentFunction
-- transform a T to a USupplier
-- provide an instance of a T (such as a factory)UnaryOperator
-- a unary operator from T -> TBinaryOperator
-- a binary operator from (T, T) -> T
In addition to these interfaces, there are primitive versions of many of these as well. This should give you a great starting point for using lambda expressions.
Gangnam Style Names and Function
When working on the previous example, I decided it would be nice to have a flexible printing system for the Person
class. One feature requirement is to display names in both a western style and an Asia style. In the west, names are displayed with the given name first and the surname second. In many Asian cultures, including Korea, names are displayed with the surname first and the given name second. In honor of Psy's very fun video, the Asian name display style will be called "Gangnam" style.
An Old Style Example
Here is an quick old style example of how I might have implemented a Person
printing class without lambda.
PersonWriterOld.java
1 package com.example.lambda;
2
3 import java.util.List;
4 import java.util.function.Function;
5
6 /**
7 * @author MikeW
8 */
9 public class PersonWriterOld {
10
11
12 public void writeShortWesternName(List<Person> pl){
13
14 System.out.println("=== Short Western List ===");
15
16 for (Person p:pl){
17 System.out.println("\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" +
18 "EMail: " + p.getEmail() + "\n" +
19 "Phone: " + p.getPhone());
20 }
21
22 }
23
24 public void writeShortGangnamName(List<Person> pl){
25
26 System.out.println("=== Short Gangnam List ===");
27
28 for (Person p:pl){
29 System.out.println("\nName: " + p.getSurName() + " " + p.getGivenName() + "\n" +
30 "EMail: " + p.getEmail() + "\n" +
31 "Phone: " + p.getPhone());
32 }
33
34 }
35
36 public void writeFullWesternName(List<Person> pl){
37
38 System.out.println("=== Full Western List ===");
39
40 for (Person p:pl){
41 System.out.println("\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" +
42 "Age: " + p.getAge() + " " + "Gender: " + p.getGender() + "\n" +
43 "EMail: " + p.getEmail() + "\n" +
44 "Phone: " + p.getPhone() + "\n" +
45 "Address: " + p.getAddress());
46 }
47
48 }
49
50
51 public void writeFullGangnamName(List<Person> pl){
52
53 System.out.println("=== Full Gangnam List ===");
54
55 for (Person p:pl){
56 System.out.println("\nName: " + p.getSurName() + " " + p.getGivenName() + "\n" +
57 "Age: " + p.getAge() + " " + "Gender: " + p.getGender() + "\n" +
58 "EMail: " + p.getEmail() + "\n" +
59 "Phone: " + p.getPhone() + "\n" +
60 "Address: " + p.getAddress());
61 }
62
63 }
64
65 }
Note the repetitive pattern. We have a separate method and loop for each style of printing.
The Function
Interface
The Function
interface is perfect for this problem. Its only method apply
has the following signature.
public R apply(T t){ }
So it takes a generic class T
and returns a generic class R
. So for this example, pass the Person
class and return a String
. A rewrite of the PersonWriter
class yields the following:
PersonWriterNew.java
1 package com.example.lambda;
2
3 import java.util.List;
4 import java.util.function.Function;
5
6 /**
7 *
8 * @author MikeW
9 */
10 public class PersonWriterNew {
11
12 public void printLambdaList(List<Person> pl, Function<Person,String> f, String description){
13 System.out.println(description);
14 for (Person p:pl){
15 System.out.println(f.apply(p));
16 }
17 }
18
19 }
Now that is quite a bit simpler. A List
, a Function
, and the title for the list is passed to a single method. The apply
method prints each Person
based on what was passed in.
So how are the Function
s defined? Here is the test code which calls the previous class.
NameTestNew.java
1 package com.example.lambda;
2
3 import java.util.List;
4 import java.util.function.Function;
5
6 /**
7 * @author MikeW
8 */
9 public class NameTestNew {
10
11 public static void main(String[] args) {
12
13 System.out.println("\n==== NameTestNew02 ===");
14
15 List<Person> list1 = Person.createShortList();
16 PersonWriterNew pw = new PersonWriterNew();
17
18 // Define Lambda Functions
19 Function<Person, String> shortWestern = p -> {
20 return "\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" +
21 "EMail: " + p.getEmail() + "\n" +
22 "Phone: " + p.getPhone();
23 };
24
25
26 Function<Person, String> shortGangnam = p -> "\nName: " +
27 p.getSurName() + " " + p.getGivenName() + "\n" +
28 "EMail: " + p.getEmail() + "\n" +
29 "Phone: " + p.getPhone();
30
31
32 Function<Person, String> fullWestern = p -> {
33 return "\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" +
34 "Age: " + p.getAge() + " " + "Gender: " + p.getGender() + "\n" +
35 "EMail: " + p.getEmail() + "\n" +
36 "Phone: " + p.getPhone() + "\n" +
37 "Address: " + p.getAddress();
38 };
39
40 Function<Person, String> fullGangnam = p -> "\nName: " + p.getSurName() + " "
41 + p.getGivenName() + "\n" + "Age: " + p.getAge() + " " +
42 "Gender: " + p.getGender() + "\n" +
43 "EMail: " + p.getEmail() + "\n" +
44 "Phone: " + p.getPhone() + "\n" +
45 "Address: " + p.getAddress();
46
47 // print list
48 pw.printLambdaList(list1, shortWestern, "\n==== Short Western Style ====");
49 pw.printLambdaList(list1, fullGangnam, "\n==== Full Gangnam Style ====");
50
51 }
52 }
Each print behavior is assigned to a Function
. Note how the Person
and String
classed are part of the variable defintion. Also, examine the examples closely. Notice that the printing code can be defined as a lambda expression statement or as a block with a return
statement.
The lambda expressions could very easily be incorporated into a Map
making their reuse much easier.
Sample Output
Here is some sample output from the program.
==== Short Gangnam Style ==== Name: Baker Bob EMail: bob.baker@example.com Phone: 201-121-4678 Name: Doe Jane EMail: jane.doe@example.com Phone: 202-123-4678 Name: Doe John EMail: john.doe@example.com Phone: 202-123-4678 Name: Johnson James EMail: james.johnson@example.com Phone: 333-456-1233 Name: Bailey Joe EMail: joebob.bailey@example.com Phone: 112-111-1111 Name: Smith Phil EMail: phil.smith@examp;e.com Phone: 222-33-1234 Name: Jones Betty EMail: betty.jones@example.com Phone: 211-33-1234
Resources
The NetBeans project and all the course code is included in the following zip file.