@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
Use functional abstractions such as Maybe, Either, handling exception cases with Try...
Keep reading or go to docs.
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
Fnz is available at jcenter:
repositories {
jcenter()
}
and then add the latest Fnz dependency:
compile 'fnz:fnz:1.0.5'
Let's review some basic examples:
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 ?:)
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) }