Adding more functional spice to Java with FunctionalJ.
Java is not a functional language. So thus Scala, F# nor PureScript. In these languages, side effects can exist at any time. But all three of these are associated with functional programming (FP). This shows that even without strict purity, a programming language can be functional. In a certain degree, functional at a style of programming. FunctionalJ (FJ) provides a number of features that make it easy to write Java in the functional style. This article discusses how FJ helps with this at a VERY high level. The aim is to map what FP offers to how they help us writing FP in Java. It is likely that the limit space here might not be clear enough so please visit FunctionalJ website and its GitHub page for more information.
I promise to add more example and tutorial later on. :-)
FunctionalJ is a library for writing functional-style code in Java. It aims to be a practical expansion to functional programming added in Java 8. FunctionalJ is a pure Java library with all code written in Java so its usages will be just like other Java library. No additional build steps or tools are required outside of adding dependencies.
Here are some features:
- Accesses and Lenses
- Pipeable (flow) and PipeLine (point-free style of programming)
- Lazy functional list and map
- Addition to Stream and Iterator
- Algebraic data types
- Rule type to constrain existing types.
- Ref for implicit context and dependency injection
- DeferAction, Promise and IO for side effect management
Recalling the previous article on the foundation and principles of functional programming -- here , those are Functions, Purity, Immutability, Graceful Error Handling, Composition, Declarative and Totalism. Now let see how FunctionalJ features allow Java code to follow the principles.
Java 8 has many built-in interfaces representing function types. FunctionalJ provides more of these, there are functions for up to 6 parameters for example. Like Java 8, FJ functions can be passed around as parameters and return type. Functions in FJ has some more interesting features.
- Easy partial application as well as automatically curried.
- Functions body can throw an exception but can be called exception free or transformed exception free function
- Can have flexible inputs -- functor agnostic -- makes a function more reusable
- Can be made to show name or location when
These features should make it easy to write FP in java.
Java 8 has many buildin interface representing function types. FunctionalJ provides more of these, there are functions for upto 6 parameters for example. Like Java 8, FJ functions can be passed around as parameters and return type. Functions in FJ has some more interesting features. FJ also coems with Ref -- non-class-base default value provider -- which can be used to do dependency injection for functions.
It is easy to compose functions together in FJ.
then(...) method that creates a function combining the current function with the given.
Then, there is PipeLine to compose functions in advance.
Functor agnostic functions can also be used to composed functions with multiple parameters.
Many classes/interfaces in FJ has declarative API.
One example is Function which as method
whenAbsentUse(...) which specify what to return in case the result of the function is null or exception.
FJ also comes with FuncList and FuncMap with (in a similar spirit to Java 8) hides all moving parts while allow customization in a declarative fashion.
Unfortunately, there is nothing much we can do when it comes to restricting purity in Java. Well, it is possible to do but not without quite an effort. That being said, FJ provides features to separate effect-full program and effect-free program. FJ has DeferAction and Promise as well as IO. The aims of these are to allow functional programming to effects but at the same time allow such separation. DeferAction specifies what action to do and how to do it (like async or retry) -- the impure part. DeferAction produces Promise. Promise only concern that to do to the result -- the pure part. DeferAction and Promise are one-time use to so that its operation only runs once. IO creates DeferAction which allows delay execution, strategic retry, and loops. With flexible-input function, a regular function can be used with all these abstractions without modification.
Most data structures in FJ are immutable -- FuncList, FuncMap, Result for example. FJ also has Struct which generates custom value data which is immutable. The generated classes also come with methods to do immutable modifications (create a new object containing the changes). There also lenses that make immutable modifications of object tree easy.
Graceful Error Handling
A function in FJ can throw an exception (include the check one) and it is made this way because exceptions are an integral part of Java -- whether you like it or not, ignoring them does not make them gone away.
Instead, FJ functions can be applied safely and return a
Result object that may hold the return value or exception.
Most of FJ abstractions also employ Functor pattern (the map method) that can be used to gracefully handle exceptions.
Last but not least, Pipeable and PipeLine also have a way to specify errors that might occur.
FJ comes with Struct, Choice and Rule types which simulate algebraic data types. Struct represents the product type. Choice represents the sum type implemented using the sealed class pattern. It also comes with pattern matching. Rule types enable validation to existing types. All these (also with the obvious Optional and Result types) allow us to narrow down valid input and output.
FunctionaJ provides many features to help use writing functional code in Java. These cover all principles of functional programming as far as the language and time allow.