Using Apache Commons Functor functional interfaces with Java 8 lambdas
Apache Commons Functor (hereon [functor]) is an Apache Commons component that provides a functional programming API and several patterns implemented (visitor, generator, aggregator, etc). Java 8 has several nice new features, including lambda expressions and functional interfaces.
In Java 8, lambdas or lambdas expressions are closures that can be evaluated and behave like anonymous methods.
Functional interfaces are interfaces with only one method. These interfaces can be used in lambdas and save you a lot of time from writing anonymous classes or even implementing the interfaces. [functor] provides several functional interfaces (thanks to Matt Benson). It hasn’t been released yet, but there are some new examples in the project site, in the trunk of the SVN.
I will use one of these examples to show how [functor] functional interfaces can be used in conjunction with Java 8 lambdas. After the example with [functor] in Java 8, I will explain how I am running Java 8 in Eclipse (it’s kind of a gambiarra, but works well).
[functor] example
Here is a simple example with one Predicate.
List numbers = Arrays.asList(1, 2, 3, 4); UnaryPredicate isEven = new UnaryPredicate () { public boolean test(Integer obj) { return obj % 2 == 0; } }; for( Integer number : numbers ) { if (isEven.test(number)) { System.out.print(number + ' '); } }
It prints only the the even numbers, those that pass by the predicate test.
[functor] example with lambdas
This modified version is using Java 8 lambdas
List numbers = Arrays.asList(1, 2, 3, 4); UnaryPredicate isEven = (Integer obj) -> { return obj % 2 == 0; }; for( Integer number : numbers ) { if (isEven.test(number)) { System.out.print(number + " "); } }
The behaviour is the same. UnaryPredicate is a functional interface. Its only method is boolean test(A obj);
. And when used in a lambda expression you just have to provide the right number of arguments and implement the closure code.
The difference in the two code snippets are the way that the UnaryPredicate for even numbers is created. Below you can see the two ways of creating this predicate, with and without Java 8 lambdas.
// pre-java-8 UnaryPredicate isEven = new UnaryPredicate() { public boolean test(Integer obj) { return obj % 2 == 0; } }; // with lambda-8 UnaryPredicate isEven = (Integer obj) -> { return obj % 2 == 0; };
Java 8 in Eclipse
Eclipse 8 doesn’t support Java 8, so you have to create a new builder in order to have Eclipse compiling your project’s sources. For a complete step-by-step guide on how to set up Eclipse Juno and Java 8, please refer to http://tuhrig.de/?p=921. I will summarize the steps here, and will show how to include [functor] jar to the project classpath.
- Download the JDK from http://jdk8.java.net/lambda and install it (I installed in /opt/java/jdk1.8.0)
- Create a new Java project in Eclipse (try-lambdas in my case)
- Disable the default Java Builder from your Eclipse project, as it doesn’t work with Java 8
- Create a new builder. When prompted with a screen that lets you browse for a program, select Java 8 javac (for me it was /opt/java/jdk1.8.0/bin/javac)
- Add the arguments below to your builder:
-classpath %CLASSPATH%;commons-functor-1.0-SNAPSHOT-jar-with-dependencies.jar;. -source 8 -d ${workspace_loc:/lambdas}/bin ${workspace_loc:/Java8}/src/lambdas/*.java
You have to include [functor]‘s jar, as well as its dependencies. For the sake of convenience, I used maven-assembly-plugin to generate a jar with dependencies for [functor]. The code and the jar are available from this GitHub repository. Or if you prefer generate your own [functor] jar with dependencies, check out the code from the repository as below.
svn checkout https://svn.apache.org/repos/asf/commons/sandbox/functor/trunk/ commons-functor
And finally include the following to [functor] pom.xml before running mvn clean assembly:assembly
.
<plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.3</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin>
Reference: Using Apache Commons Functor functional interfaces with Java 8 lambdas from our JCG partner Bruno Kinoshita at the Kinoshita’s blog blog.
now we have Google Guava so Apache Commons Functor may be forgotten