Can we make working with functions easier in Java 8?

John McClean
3 min readFeb 4, 2016

--

Beveridges law of headlines states

“Any headline that ends in a question mark can be answered by the word no.”

But we’re going to debunk that in this article, because the answer is a resounding yes. Let’s take a look at the FluentFunctions feature in cyclops 7.3.0

Capturing a function

We can capture a function (or method reference) to work with via FluentFunctions.of

Working with functions

Once we’ve captured a function or method reference, FluentFunctions provides a nice simple API to perform a large range of powerful actions including

  1. Function execution / application (via apply)
  2. Build retry functionality, seamlessly, into the execution of function
  3. Logging and println functionality
  4. Build error handling and recovery seamlessly, into the execution of the function
  5. Leverage Aspect Oriented Programming cleanly, in standard easy to follow and debug Java without byte and dependency injection magic
  6. Add caching functionality (backed by your cache of choice), seamlessly into the function execution path
  7. Execute the function asynchronously
  8. Apply advanced pattern matching to transform the output of our function
  9. Generate a stream from the function
  10. Advanced:: Use JDK and external ‘monads’ to inject additonal functionality into the function (e.g. use Optional to handle nulls)
  11. Advanced:: Can be used as a “Reader monad” to implement dependency injection without a framework (for an example see https://medium.com/@johnmcclean/dependency-injection-using-the-reader-monad-in-java8-9056d9501c75)

Leveraging Retry Functionality

In the example below we will retry our execution of exceptionalFirstTime 500 ms after the first failure, for a maxium of 2 attempts

Leveraging Recover Functionality

In the example we can recover from IOExceptions, adding the suffix boo! to the input to the failed method call. The println operator also prints any inputs and outputs to the console.

Leveraging AOP

It is straightforward to apply before, after and around advice making use of cyclops FluentFunctions.

Leveraging Caching Functionality with FluentFunctions

We can use the memoize operator to cache the result for any given input.

Calling fn.apply(10) multiple times, results in only one underlying call to addOne.

fn.apply(10);
fn.apply(10);
fn.apply(10);

called is 1

Leveraging external caching libraries

If you need to take advantage of deeper caching functionality we can also plugin external cache implementations such as Guava or Caffiene.

Making use of pattern matching

In the example below we match against the output of addOne with a single case (checking for the value 2 and returning 3 if it matches).

Further Reading

FluentFunctions User Guide : http://gist.asciidoctor.org/?github-aol/cyclops-react//user-guide/lambdas.adoc#_fluentfunctions

Pattern matching in cyclops-react : http://gist.asciidoctor.org/?github-aol/cyclops-react//user-guide/pattern-matching.adoc

--

--

John McClean

Architecture @ Verizon Media. Maintainer of Cyclops. Twitter @johnmcclean_ie