Vavr Option workshop.
test/groovy/Workshop
test/groovy/Answers
(same tests as in Workshop
but correctly solved)Optional
, but with bigger, more flexible APIinterface Option<T> extends Value<T>, Serializable
interface Value<T> extends Iterable<T>
Option
is isomorphic to singleton list (either has element or not, so it could be treated as collection)final class Some<T>
final class None<T>
None
instance is a singletonnull
inside map
does not cause Option
switch to None
(contrary to Optional
)
expect:
Option.some(2).map(alwaysNull).defined
Optional.of(2).map(alwaysNull).empty
Some(null)
, so NPE
is possible even on defined Option
findById
)Optional
hasOption<T>
<-> Optional<T>
Option.ofOptional
option.toJavaOptional()
List<Option<T>> -> Option<List<T>>
Option.sequence(list)
Options
are None
- returns None
static Option<T> when(boolean condition, Supplier<? extends T> supplier)
Option<R> collect(PartialFunction<? super T, ? extends R> partialFunction)
None
None
Option<T> onEmpty(Runnable action)
Some
Option<T> peek(Consumer<? super T> action)
Optional
since 11)Option<T> orElse(Supplier<? extends Option<? extends T>> supplier)
transform
function could be nearly always replaced with more expressive and natural map(...).orElse(...)
same as
given:
Function<Option<Integer>, String> transformer = { it.isEmpty() ? '' : it.get().toString() }
expect:
Option.of(5).transform(transformer) == '5'
given:
Function<Option<Integer>, String> transformer = { it.isEmpty() ? '' : it.get().toString() }
expect:
transformerFive = Option.of(5)
.map { it.toString() }
.orElse('') == '5'
Option<T>
<-> List<T>
option.toList()
list.toOption()
boolean contains(T element)
boolean exists(Predicate<? super T> predicate)
boolean forAll(Predicate<? super T> predicate)
Some
return (obj == this) || (obj instanceof Some && Objects.equals(value, ((Some<?>) obj).value));
None
return o == this
map does not breaks monadic laws
given:
Function<Integer, Integer> alwaysNull = { null }
Function<Integer, String> safeToString = { nonNull(it) ? String.valueOf(it) : 'null' }
Function<Integer, String> composition = alwaysNull.andThen(safeToString)
expect:
Optional.of(1).map(composition) != Optional.of(1).map(alwaysNull).map(safeToString)
Optional.of(1).stream().map(composition).findAny() == Optional.of(1).stream()
.map(alwaysNull)
.map(safeToString)
.findAny()
Option.of(1).map(composition) == Option.of(1).map(alwaysNull).map(safeToString)