FλZ

Groovy functional library


Find Out More

FNZ adds functional abstractions to Groovy language!

Use functional abstractions such as Maybe, Either, handling exception cases with Try...
Keep reading or go to docs.

Grab

Try your Hello world with Grab

@Grab('fnz:fnz:1.0.5')
@GrabResolver('http://dl.bintray.com/marioggar/maven')
def failure = Try(1) { Integer x -> x / 0 }

assert !failure.isSuccess()
assert failure.isFailure()
assert failure.or(Success(3)).get() == 3

Gradle

Fnz is available at jcenter:

repositories {
    jcenter()
}

and then add the latest Fnz dependency:

compile 'fnz:fnz:1.0.5'

Getting Started

Let's review some basic examples:

Maybe

All abstractions are available at fnz.Fnz as static functions.

import fnz.Fnz

The following example is really simple, just adding one to a value, only if the value is null then use zero instead:

assert 1 == Fnz.Maybe(null).or(Fnz.Just(0)).get() + 1

IMPORTANT: If you use Fnz in Groovy code, you don’t have to import the Fnz class, Fnz has an extension module that exposes directly all those functions for you.

assert 1 == Maybe(null).or(Just(0)).get() + 1

Ok, but…​ Groovy already has the Elvis operator, which is simpler, and less verbose.. so why should I use this anyway ?

Well if you’re only evaluating a value this may sound overkill, but if you would like to concatenate a set of operation over a possible null value, then it could be very helpful:

assert Maybe(null)
       .or(Just(0))
       .fmap { x -> x + 1 }
       .fmap { y -> y + 1 }
       .get() == 2

And the plain Groovy code:

assert (null ?: 0)
    .collect { x -> x + 1 }
    .collect { y -> y + 1 }
    .find() == 2

Wait! plain Groovy is not that bad, I think I stick to Elvis, Do you have anything else to show ? Yes I do! Can you call a method depending on null ? No right ? And that makes you whether use a default parameter or have another conditional statement.

Having a type representing the null value enables programmer to override methods depending on whether the value was Nothing or Just. It’s just not possible to do that with plain Groovy (even though null is an instance of org.codehaus.groovy.runtime.NullObject). Lets see this subject:

void 'invoking a method depending on Maybe'() {
    when: 'having a null reference'
    def number = Maybe(null) // == Nothing()
    def result = execute(number)

    then: 'we should get a bad result'
    result == 'bad'
}

String execute(fnz.data.Maybe.Nothing nothing) {
    return 'bad'
}

String execute(fnz.data.Maybe.Just value) {
    return 'good'
}

No conditionals required…​ Elvis has left the building ?:)

Try

The Try abstraction is a different way of dealing with exceptions in your apps. Instead of writing a try-catch block just make your computation to return a value. Basically if an exception is thrown you’ll get a fnz.data.Try.Failure instance that will contain both the value that produced the exception and the exception itself.

On the other hand if everything goes ok you’ll get a fnz.data.Try.Success instance with the value produced by the computation.

In the following example we’re using the Try(T,Function<A,B>) from class fnz.Fnz function. This function receives a value and a function. Because the example is Groovy we normally use a Closure but if you’re using Java you could be using an instance of fnz.data.Function.

void 'get result from an unsafe operation'() {
    when: 'trying to apply a value to an unsafe operation'
        // 'two' and 'four' will throw an Exception!
        def numbers = ['1', 'two', '3', 'four']
           .collect { String n -> Try(n) { it.toInteger() }  }
           .findAll() // Using Groovy Truth

    then: 'we should get the successful values'
        numbers*.get() == [1, 3] // Failure results have been filtered

}

Please notice that the second parameter of a Try function is a function itself (A closure representing a function) so you can also pass a method reference

.collect { String n -> Try(n, Integer.&parseInt) }

Check out the rest of the documentation!

Or checkout the code at Github


FNZ 2015