@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) }