1. yourvirtualclass.com
New Features in Core Java 8
Lesson 1 - Functional Interfaces
Section 1 - What is a functional interface?
Functional interfaces do one thing. They have one abstract method (called a functional method),
which needs to be implemented by the programmer.
We have been using functional interfaces all along. The ActionListener interface defines the
actionPerformed() method which we need to implement. The Comparator interface defines
the compare() method.
Consider the functional interface Callable:
public interface Callable<V> {
public V call();
};
We can define a class which implements it by defining the call() method in the class :
class MyCallable implements Callable<Integer>
{
@Override public Integer call() { return 5; }
}
To avoid naming a new class, we can implement it anonymously:
Callable myAnomObj= new Callable<Integer>() {
@Override public Integer call() { return 6; }
};
In Java 8, we can also assign an existing method to the call() method of Callable:
public static Integer call() { return 7; }
public static Integer caller(Callable c) throws Exception {
return (Integer)c.call();
2. }
caller(CLASSNAME::call);
CLASSNAME::call is a reference to the static method call() in class CLASSNAME (method
references are discussed in detail in lesson 6).
When caller() executes the call() method of its formal parameter of type interface Callable() it is
really executing static method call() to which it is assigned.
Listing 1 - TestCallable.java
import java.util.concurrent.Callable;
class MyCallable implements Callable<Integer>
{
@Override public Integer call() { return 5; }
}
public class TestCallable {
public static Integer call() { return 7; }
public static Integer caller(Callable c) throws Exception {
return (Integer)c.call();
}
public static void main(String[] args) {
Callable myAnomObj= new Callable<Integer>() {
@Override public Integer call() { return 6; }
};
MyCallable myCallObj = new MyCallable();
try {
System.out.println("myCallObj : " + myCallObj.call());
System.out.println("myAnomObj : " + myAnomObj.call());
System.out.println("TestCallable::call : " + caller(TestCallable::call));
} catch (Exception e) {}
}
}
OUTPUT:
myCallObj : 5
myAnomObj : 6
TestCallable::call : 7
3. Section 2 - Predicate
Let’s consider the functional interface Predicate:
@FunctionalInterface
public interface Predicate<T> {
public boolean test(T t);
};
This generic interface has functional method test() which takes an argument of type T and
returns true or false. It is ideal for asking a question.
As with Callable, we can define a class which implements it by defining the test() method in the
class :
class MyPredicate implements Predicate<Integer>
{
@Override public boolean test(Integer i) { return i > 5; }
}
We can also implement it anonymously:
Predicate myAnomObj= new Predicate<Integer>() {
@Override public boolean test(Integer i) { return (i%2)==0? true:false; }
};
We can also assign an existing method to the test() method of Predicate:
public static boolean test(Integer i) { return (i%2)!=0? true:false; }
public static boolean tester(Integer i, Predicate<Integer> t) {
return t.test(i);
}
tester(7,CLASSNAME::test);
Listing 2 - TestPredicate.java
import java.util.function.Predicate;
class MyPredicate implements Predicate<Integer>
{
@Override public boolean test(Integer i) { return i > 5; }
}
public class TestPredicate {
4. public static boolean test(Integer i) { return (i%2)!=0? true:false; }
public static boolean tester(Integer i, Predicate<Integer> t) {
return t.test(i);
}
public static void main(String[] args) {
Predicate myAnomObj= new Predicate<Integer>() {
@Override public boolean test(Integer i) { return (i%2)==0? true:false; }
};
MyPredicate myPredObj = new MyPredicate();
System.out.println(myPredObj.test(7));
System.out.println(myPredObj.test(4));
System.out.println(myAnomObj.test(7));
System.out.println(myAnomObj.test(4));
System.out.println(tester(7,TestPredicate::test));
System.out.println(tester(4,TestPredicate::test));
}
}
OUTPUT
true
false
false
true
true
false
The Java 8 Functional interfaces were designed to be used as assign targets for lambda
expressions and method references. It is not necessary to create a separate class or
anonymous
class to implement a functional interface. But since lambda expressions are a study unto
themselves (and addressed in detail in Lesson 2), we will use method references for the
remainder of this lesson.
LAB1: Write a program with a Predicate that returns true if a String is longer than
ten characters. Call the Predicate with a method reference.
Section 3 - Predicate Helper Methods
5. Functional interfaces often have default and static methods (discussed in detail in lesson 5) in
addition to their functional method. These methods are referred to as Helper Methods.
Section 3a - Predicate negate
Predicate’s negate() method causes the test() method to return true if test’s condition is false.
default Predicate<T> negate()
The following program negates the condition in test() by causing odd input to result in false
when tested for oddness:
Listing 3 - PredicateNegate.java
import java.util.function.Predicate;
public class PredicateNegate {
public static boolean test(Integer i) { return (i%2)!=0? true:false; }
public static boolean tester(Integer i, Predicate<Integer> t) {
return t.negate().test(i);
}
public static void main(String[] args) {
System.out.println(tester(7,PredicateNegate::test));
}
}
OUTPUT
false
Section 3b - Predicate And
Predicate’s and() method logically ANDs its test() operation with another predicate. The
compound predicate is short-circuited (if the first operation is false, the second is not
performed).
default Predicate<T> and(Predicate<? super T> other)
Although this operation is normally performed in collection chains (Lesson 6), we can
demonstrate with our method reference approach by calling and() with the second predicate
before calling test().
6. The following program checks if an Integer is divisible by 4 (the first predicate) before checking if
it is even (the and() operation of the second predicate):
Listing 4 - PredicateAnd.java
import java.util.function.Predicate;
public class PredicateAnd {
static int order = 0;
public static boolean isEven(Integer i) {
order+= 5;
return (i%2)==0? true:false;
}
public static boolean divBy4(Integer i) {
order+= 2;
return (i%4)==0? true:false;
}
public static boolean tester(Integer i, Predicate<Integer> t, Predicate<Integer> u) {
return t.and(u).test(i);
}
public static void main(String[] args) {
order = 0;
System.out.println(tester(6,PredicateAnd::divBy4,PredicateAnd::isEven));
System.out.println("order="+order);
order = 0;
System.out.println(tester(8,PredicateAnd::divBy4,PredicateAnd::isEven));
System.out.println("order="+order);
}
}
OUTPUT:
false
order=2
true
order=7
The order field demonstrates the short-circuiting. Integer 6 is checked to be divisible by 4, and
order is incremented to 2. Since the and() predicate [divBy4] fails, the test predicate [isEven] is
not executed and order is still 2. Integer 8 is checked to be divisible by 4, and order is
incremented to 2. Since the and() predicate [divBy4] succeeds, the test predicate [isEven] is
executed and order is incremented to 7.
LAB2: Given the following class:
7. class Person {
public String Name;
public int social_security_number;
}
Use Predicates to first check if a Person’s name is “George” and then check if his
that his social security number is 123456789.
Section 3c - Predicate Or
Predicate’s or() method logically ORs its test() operation with another predicate. The compound
predicate is short-circuited (if the first operation is true, the second is not performed).
default Predicate<T> or(Predicate<? super T> other)
The following program checks if an Integer is divisible by 4 (the or() operation of the second
predicate) before checking if it is even (the first predicate):
The following program also checks for divisibility by 4 before checking for evenness. It doesn’t
check for evenness if the input is divisible by 4. Stated differently, it doesn’t evaluate the second
predicate if the first predicate is true:
Listing 5 - PredicateOr.java
import java.util.function.Predicate;
public class PredicateOr {
static int order = 0;
public static boolean isOdd(Integer i) {
order+= 5;
return (i%2)==0? true:false;
}
public static boolean divBy4(Integer i) {
order+= 2;
return (i%4)==0? true:false;
}
public static boolean tester(Integer i, Predicate<Integer> t, Predicate<Integer> u) {
return t.or(u).test(i);
}
public static void main(String[] args) {
order = 0;
System.out.println(tester(5,PredicateOr::divBy4,PredicateOr::isOdd));
8. System.out.println("order="+order);
order = 0;
System.out.println(tester(8,PredicateOr::divBy4,PredicateOr::isOdd));
System.out.println("order="+order);
}
}
OUTPUT
false
order=7
true
order=2
5 is not divisible by 4 so the second predicate must be evaluated, and order = 2 + 5 =7.
8 is divisible by 4 so the second predicate is not evalated, and order = 2.
LAB3: Use Predicates to check if a Person’s Name is either “Santa Claus”, or “Easter
Bunny”, or “Mother Nature”, or “Tooth Fairy”.
Section 3d - Predicate isEqual
Predicate’s static isEqual() method creates a predicate from any object. The predicate returns
true if the argument to its test() method is equal to the object used to build the predicate
according to the overridden equals() method of Object.
static <T> Predicate<T> isEqual(Object targetRef)
The test method from a Predicate created using isEqual() can be called directly, or it can
participate in a series of predicate operations as shown in the following program:
Listing 6 - PredicateIsEqual.java
import java.util.function.Predicate;
public class PredicateIsEqual {
public static boolean isEven(Integer i) { return (i%2)==0? true:false; }
public static boolean tester(Integer i, Predicate<Integer> t, Predicate<Integer> u) {
return t.and(u).test(i);
}
public static void main(String[] args) {
Predicate<Integer> t = Predicate.isEqual(4);
System.out.println(t.test(4));
9. System.out.println(tester(6,PredicateAnd::isEven,Predicate.isEqual(6)));
System.out.println(tester(8,PredicateAnd::isEven,Predicate.isEqual(7)));
}
}
OUTPUT:
true
true
false
Section 4 - Function
Function is a functional interface with functional method apply() which takes an input of type T
and returns an object of type R. It is ideal for converting an object to an object of another type.
@FunctionalInterface
public interface Function<T,R> {
public R apply(T t);
};
The following program converts a String to an Integer through the Function interface (which is
assigned to the TestFunction::apply() method) :
Listing 7 - TestFunction.java
import java.util.function.Function;
public class TestFunction
{
public static Integer apply(String s) { return Integer.parseInt(s); }
public static Integer applier(String s, Function<String,Integer> f) {
return f.apply(s);
}
public static void main(String[] args)
{
System.out.println(applier("9",TestFunction::apply));
}
}
OUTPUT:
10. 9
LAB4: Write a Function which converts a Person to a String by concatenating his/her
Name and social security number.
Section 5 - Function Helper Methods
Section 5a - Function andThen
Function’s andThen() method applies an additional operation AFTER the primary operation has
been performed.
default <V> Function<T,V> andThen(Function<? super R, ? extends V> after)
The following program first converts a String to a Boolean through the first Function (whose
apply() method is assigned to applyString(). It then converts the Boolean to an Integer through
the second Function (whose apply() method is assigned to applyBoolean().
Listing 8 - FunctionAndThen.java
import java.util.function.Function;
public class FunctionAndThen {
public static Boolean applyString(String s) { return Boolean.parseBoolean(s); }
public static Integer applyBoolean(Boolean b) { return b==true? 1:0; }
public static Integer applier(String s, Function<String,Boolean> f, Function<Boolean,Integer>
g)
{
return f.andThen(g).apply(s);
}
public static void main(String[] args) {
System.out.println(applier("true",FunctionAndThen::applyString,
FunctionAndThen::applyBoolean));
}
}
OUTPUT
1
LAB5: Given the following class:
11. class Employee {
public Person;
public int salary;
}
Write a Function which converts an Employee to a Person by concatenating
his/her salary with the Person’s Name. Then use the Function from LAB4 to
convert the Person to a String.
Section 5b - Function compose
Function’s compose() method applies an additional operation BEFORE the primary operation
has been performed.
default <V> Function<V,R> compose(Function<? super V, ? extends T> after)
The following program does the same thing as FunctionAndThen.java using compose() instead
of andThen(). Since the method assigned to compose() is executed first, applyBoolean()
becomse the primary function:
Listing 9 - FunctionCompose.java
import java.util.function.Function;
public class FunctionCompose {
public static Integer applyBoolean(Boolean b) { return b==true? 1:0; }
public static Boolean applyString(String s) { return Boolean.parseBoolean(s); }
public static Integer applier(String s, Function<Boolean,Integer> f, Function<String,Boolean>
g) {
return f.compose(g).apply(s);
}
public static void main(String[] args) {
System.out.println(applier("true",FunctionCompose::applyBoolean,
FunctionCompose::applyString));
}
}
OUTPUT
1
12. Section 5c - Function identity
Function’s static identity() method converts an input to itself. Stated differently, it creates a
Function whose apply() method always returns its input.
static default <T> Function<T,T> identity()
Listing 10 - FunctionIdentity.java
import java.util.function.Function;
public class FunctionIdentity {
public static void main(String[] args) {
Function<String,String> f = Function.identity();
System.out.println(f.apply("HELLO"));
System.out.println(f.apply("WORLD"));
}
}
OUTPUT
HELLO
WORLD
Copyright 2016 YourVirtualClass.com. All rights reserved.