Paul Campbell
a501c506a4
* Update copyright year * Alias: added * bump release-drafter from 5.11.0 to 5.14.0 * Version set to 2.3.0 * Rename Alias as Wrapper and drop map method Simplify tests. |
||
---|---|---|
.github | ||
images | ||
src | ||
.gitignore | ||
CHANGELOG.org | ||
Jenkinsfile.groovy | ||
LICENSE.txt | ||
lombok.config | ||
pom.xml | ||
README.org |
- Mon
- Alias, TypeAlias, Maybe and Result for Java.
- Maven Usage
- Wrapper
- TypeAlias
- Maybe
Maybe
is a Monad:- Static Constructors
- Instance Methods
Maybe<T> filter(Predicate<T> predicate)
<R> Maybe<R> map(Function<T,R> f)
<R> Maybe<R> flatMap(Function<T,Maybe<R>> f)
void match(Consumer<T> just, Runnable nothing)
<R> R matchValue(Function<T, R> justMatcher, Supplier<R> nothingMatcher)
T orElse(T otherValue)
T orElseGet(Supplier<T> otherValueSupplier)
T or(Supplier<Maybe<T> alternative)
void orElseThrow(Supplier<Exception> error)
Maybe<T> peek(Consumer<T> consumer)
void ifNothing(Runnable runnable)
Stream<T> stream()
boolean isJust()
boolean isNothing()
Optional<T> toOptional()
- Result
Result
is a Monad- Static Constructors
- Static Methods
- Instance Methods
<R> Result<R> map(Function<T,R> f)
<R> Result<R> flatMap(Function<T,Result<R>> f)
<R> Result<R> andThen(Function<T,Callable<R>> f)
void match(Consumer<T> onSuccess, Consumer<Throwable> onError)
Result<T> recover(Function<Throwable,Result<T>> f)
Result<T> peek(Consumer<T> consumer)
Result<T> thenWith(Function<T,WithResultContinuation<T>> f)
Result<Maybe<T>> maybe(Predicate<T> predicate)
T orElseThrow()
<E extends Exception> T orElseThrow(Class<E> type) throws E
T orElseThrowUnchecked()
void onError(Consumer<Throwable> errorConsumer)
boolean isOkay()
boolean isError()
- Tree
- TreeBuilder
- Lazy
- Either
Either
is not a Monad.- Static Constructors
- Instance Methods
boolean isLeft()
boolean isRight()
void match(Consumer<L> onLeft, Consumer<R> onRight)
<T> Either<T, R> mapLeft(Function<L, T> f)
<T> Either<L, T> mapRight(Function<R, T> f)
<T> Either<T, R> flatMapLeft(Function<L, Either<T, R>> f)
<T> Either<T, R> flatMapRight(Function<L, Either<T, R>> f)
Optional<L> getLeft()
Optional<R> getRight()
Mon
Alias, TypeAlias, Maybe and Result for Java.
file:https://img.shields.io/nexus/r/https/oss.sonatype.org/net.kemitix/mon.svg?style=for-the-badge file:https://img.shields.io/maven-central/v/net.kemitix/mon.svg?style=for-the-badge
- [Maven Usage]
- [Alias]
- [TypeAlias]
- [Maybe]
- [Result]
- [Tree]
- [Lazy]
- [Either]
Maven Usage
<dependency>
<groupId>net.kemitix</groupId>
<artifactId>mon</artifactId>
<version>RELEASE</version>
</dependency>
The latest version should be shown above with the nexus and maven-central badges or can be found on Maven Central.
Wrapper
A simple FunctionalInterface that contains a value. Can be used to implement a form of type-alias in Java.
In Haskell it is possible to create an alias for a Type, and to then use that alias with the same behaviour as the original, except that the compiler doesn't treat the alias as the same Type and will generate compiler errors if you try and use them together. e.g.:
newtype PhoneNumber = PhoneNumber String
newtype Name = Name String
newtype PhoneBookEntry = PhoneBookEntry (Name, PhoneNumber)
newtype PhoneBook = PhoneBook [PhoneBookEntry]
In Java we don't have the ability to have that true alias, so Wrapper simply wraps the value within a new type. It's as close as I could get to a Haskell type alias in Java.
The benefits of using Wrapper are:
- encapsulation of the wrapped type when passing references through code that doesn't need to access the actual value, but only to pass it on
- type-safe parameters where you would otherwise be passing Strings, Integers, Lists, or other general classes
- less verbose than implementing your own
Wrapper Example:
interface PhoneNumber extends Wrapper<String> {}
PhoneNumber pn = () -> "01234 567890";
String v = pn.value();
Roll your own:
class PhoneNumber {
private final String value;
public PhoneNumber(final String value) {
this.value = value;
}
public String value() {
return value;
}
}
Lombok:
Using Lombok we can achieve it in 8 lines, compared to 24 for rolling your own, or 1 for Alias:
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class PhoneNumber {
private final String value;
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
TypeAlias
Note: this is a precursor to `Wrapper` and should be considered deprecated.
TypeAlias Example:
class PhoneNumber extends TypeAlias<String> {
private PhoneNumber(final String value) {
super(value);
}
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
TypeAlias
can be a Monad
package net.kemitix.mon;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import java.util.function.Function;
public class TypeAliasMonadTest implements WithAssertions {
private final int v = 1;
private final Function<Integer, AnAlias<Integer>> f = i -> a(i * 2);
private final Function<Integer, AnAlias<Integer>> g = i -> a(i + 6);
private static AnAlias<Integer> a(Integer v) {
return AnAlias.of(v);
}
@Test
public void leftIdentity() {
assertThat(
a(v).flatMap(f)
).isEqualTo(
f.apply(v)
);
}
@Test
public void rightIdentity_inline() {
// java isn't able to properly infer the correct types when used in-line
assertThat(
a(v).<Integer, AnAlias<Integer>>flatMap(x -> a(x))
).isEqualTo(
a(v)
);
}
@Test
public void rightIdentity_explicitValue() {
final AnAlias<Integer> integerAnAlias = a(v).flatMap(x -> a(x));
assertThat(
integerAnAlias
).isEqualTo(
a(v)
);
}
@Test
public void associativity() {
assertThat(
a(v).flatMap(f).flatMap(g)
).isEqualTo(
a(v).flatMap(x -> f.apply(x).flatMap(g))
);
}
static class AnAlias<T> extends TypeAlias<T> {
private AnAlias(T value) {
super(value);
}
static <T> AnAlias<T> of(T value) {
return new AnAlias<>(value);
}
}
}
Instance Methods
final <R> R map(final Function<T, R> f)
Map the TypeAlias into another value.
final StudentId studentId = StudentId.of(123);
final String idString = studentId.map(id -> String.valueOf(id));
class StudentId extends TypeAlias<Integer> {
private StudentId(Integer value) {
super(value);
}
static StudentId of(Integer id) {
return new StudentId(id);
}
}
final <R, U extends TypeAlias<R>> U flatMap(final Function<T, U> f)
Map the TypeAlias into another TypeAlias.
final StudentId studentId = StudentId.of(123);
final StudentName studentName = studentId.flatMap(id -> getStudentName(id));
class StudentName extends TypeAlias<String> {
private StudentName(String value) {
super(value);
}
static StudentName of(final String name) {
return new StudentName(name);
}
}
T getValue()
Get the value of the TypeAlias.
final String name = studentName.getValue();
Maybe
Allows specifying that a value may or may not be present. Similar to
Optional
. Maybe
provides additional methods that Optional
doesn't:
isNothing()
, stream()
, ifNothing()
and match()
. Maybe
does not
have a get()
method.
Unlike Optional
, when a map()
results in a null
, the Maybe
will
continue to be a Just
. Optional
would switch to being empty. vavr.io
follows the same behaviour as Maybe
.
import net.kemitix.mon.maybe.Maybe;
import java.util.function.Function;
import java.util.function.Predicate;
class MaybeExample {
public static void main(String[] args) {
Maybe.just(countArgs(args))
.filter(isEven())
.map(validMessage())
.match(
just -> System.out.println(just),
() -> System.out.println("Not an valid value")
);
}
private static Function<Integer, String> validMessage() {
return v -> String.format("Value %d is even", v);
}
private static Predicate<Integer> isEven() {
return v -> v % 2 == 0;
}
private static Integer countArgs(String[] args) {
return args.length;
}
}
In the above example, the number of command line arguments are counted, if
there are an even number of them then a message is created and printed by
the Consumer parameter in the match
call. If there is an odd number of
arguments, then the filter will return Maybe.nothing()
, meaning that the
nothing
drops straight through the map and triggers the Runnable parameter
in the match
call.
Maybe
is a Monad:
package net.kemitix.mon;
import net.kemitix.mon.maybe.Maybe;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import java.util.function.Function;
public class MaybeMonadTest implements WithAssertions {
private final int v = 1;
private final Function<Integer, Maybe<Integer>> f = i -> m(i * 2);
private final Function<Integer, Maybe<Integer>> g = i -> m(i + 6);
private static Maybe<Integer> m(int value) {
return Maybe.maybe(value);
}
@Test
public void leftIdentity() {
assertThat(
m(v).flatMap(f)
).isEqualTo(
f.apply(v)
);
}
@Test
public void rightIdentity() {
assertThat(
m(v).flatMap(x -> m(x))
).isEqualTo(
m(v)
);
}
@Test
public void associativity() {
assertThat(
m(v).flatMap(f).flatMap(g)
).isEqualTo(
m(v).flatMap(x -> f.apply(x).flatMap(g))
);
}
}
Static Constructors
static <T> Maybe<T> maybe(T value)
Create a Maybe for the value that may or may not be present.
Where the value is null
, that is taken as not being present.
final Maybe<Integer> just = Maybe.maybe(1);
final Maybe<Integer> nothing = Maybe.maybe(null);
static <T> Maybe<T> just(T value)
Create a Maybe for the value that is present.
The value
must not be null
or a NullPointerException
will be thrown.
If you can't prove that the value won't be null
you should use
Maybe.maybe(value)
instead.
final Maybe<Integer> just = Maybe.just(1);
static <T> Maybe<T> nothing()
Create a Maybe for a lack of a value.
final Maybe<Integer> nothing = Maybe.nothing();
static <T> Maybe<T> findFirst(Stream<T> stream)
Creates a Maybe from the first item in the stream, or nothing if the stream is empty.
final Maybe<Integer> just3 = Maybe.findFirst(Stream.of(3, 4, 2, 4));
final Maybe<Integer> nothing = Maybe.findFirst(Stream.empty());
Instance Methods
Maybe<T> filter(Predicate<T> predicate)
Filter a Maybe by the predicate, replacing with Nothing when it fails.
final Maybe<Integer> maybe = Maybe.maybe(getValue())
.filter(v -> v % 2 == 0);
<R> Maybe<R> map(Function<T,R> f)
Applies the function to the value within the Maybe, returning the result within another Maybe.
final Maybe<Integer> maybe = Maybe.maybe(getValue())
.map(v -> v * 100);
<R> Maybe<R> flatMap(Function<T,Maybe<R>> f)
Applies the function to the value within the Maybe
, resulting in another Maybe
, then flattens the resulting Maybe<Maybe<T>>
into Maybe<T>
.
Monad binder maps the Maybe into another Maybe using the binder method f
final Maybe<Integer> maybe = Maybe.maybe(getValue())
.flatMap(v -> Maybe.maybe(getValueFor(v)));
void match(Consumer<T> just, Runnable nothing)
Matches the Maybe, either just or nothing, and performs either the Consumer, for Just, or Runnable for nothing.
Maybe.maybe(getValue())
.match(
just -> workWithValue(just),
() -> nothingToWorkWith()
);
<R> R matchValue(Function<T, R> justMatcher, Supplier<R> nothingMatcher)
Matches the Maybe, either just or nothing, and performs either the Function, for Just, or Supplier for nothing.
final String value = Maybe.maybe(getValue())
.matchValue(
just -> Integer.toString(just),
() -> "nothing"
);
T orElse(T otherValue)
A value to use when Maybe is Nothing.
final Integer value = Maybe.maybe(getValue())
.orElse(1);
T orElseGet(Supplier<T> otherValueSupplier)
Provide a value to use when Maybe is Nothing.
final Integer value = Maybe.maybe(getValue())
.orElseGet(() -> getDefaultValue());
T or(Supplier<Maybe<T> alternative)
Provide an alternative Maybe to use when Maybe is Nothing.
final Maybe<Integer> value = Maybe.maybe(getValue())
.or(() -> Maybe.just(defaultValue));
void orElseThrow(Supplier<Exception> error)
Throw the exception if the Maybe is a Nothing.
final Integer value = Maybe.maybe(getValue())
.orElseThrow(() -> new RuntimeException("error"));
Maybe<T> peek(Consumer<T> consumer)
Provide the value within the Maybe, if it exists, to the Consumer, and returns this Maybe. Conceptually equivalent to the idea of ifPresent(...)
.
final Maybe<Integer> maybe = Maybe.maybe(getValue())
.peek(v -> v.foo());
void ifNothing(Runnable runnable)
Run the runnable if the Maybe is a Nothing, otherwise do nothing.
Maybe.maybe(getValue())
.ifNothing(() -> doSomething());
Stream<T> stream()
Converts the Maybe into either a single value stream or an empty stream.
final Stream<Integer> stream = Maybe.maybe(getValue())
.stream();
boolean isJust()
Checks if the Maybe is a Just.
final boolean isJust = Maybe.maybe(getValue())
.isJust();
boolean isNothing()
Checks if the Maybe is Nothing.
final boolean isNothing = Maybe.maybe(getValue())
.isNothing();
Optional<T> toOptional()
Convert the Maybe to an Optional.
final Optional<Integer> optional = Maybe.maybe(getValue())
.toOptional();
Result
Allows handling error conditions without the need to catch exceptions.
When a Result
is returned from a method it will contain one of two values.
Either the actual result, or an error in the form of an Exception
. The
exception is returned within the Result
and is not thrown.
import net.kemitix.mon.result.Result;
import java.io.IOException;
class ResultExample implements Runnable {
public static void main(final String[] args) {
new ResultExample().run();
}
@Override
public void run() {
Result.of(() -> callRiskyMethod())
.flatMap(state -> doSomething(state))
.match(
success -> System.out.println(success),
error -> error.printStackTrace()
);
}
private String callRiskyMethod() throws IOException {
return "I'm fine";
}
private Result<String> doSomething(final String state) {
return Result.of(() -> state + ", it's all good.");
}
}
In the above example the string "I'm fine"
is returned by
callRiskyMethod()
within a successful Result
. The .flatMap()
call,
unwraps that Result
and, as it is a success, passes the contents to
doSomething()
, which in turn returns a Result
that the .flatMap()
call
returns. match()
is called on the Result
and, being a success, will call
the success Consumer
.
Had callRiskyMethod()
thrown an exception it would have been caught by the
Result.of()
method which would have then been an error Result
. An error
Result would have ignored the flatMap
and skipped to the match()
when it
would have called the error Consumer
.
Result
is a Monad
package net.kemitix.mon;
import net.kemitix.mon.result.Result;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import java.util.function.Function;
public class ResultMonadTest implements WithAssertions {
private final int v = 1;
private final Function<Integer, Result<Integer>> f = i -> r(i * 2);
private final Function<Integer, Result<Integer>> g = i -> r(i + 6);
private static Result<Integer> r(int v) {
return Result.ok(v);
}
@Test
public void leftIdentity() {
assertThat(
r(v).flatMap(f)
).isEqualTo(
f.apply(v)
);
}
@Test
public void rightIdentity() {
assertThat(
r(v).flatMap(x -> r(x))
).isEqualTo(
r(v)
);
}
@Test
public void associativity() {
assertThat(
r(v).flatMap(f).flatMap(g)
).isEqualTo(
r(v).flatMap(x -> f.apply(x).flatMap(g))
);
}
}
Static Constructors
static <T> Result<T> of(Callable<T> callable)
Create a Result for a output of the Callable.
If the Callable throws and Exception, then the Result will be an error and will contain that exception.
This will be the main starting point for most Results where the callable
could throw an Exception
.
final Result<Integer> okay = Result.of(() -> 1);
final Result<Integer> error = Result.of(() -> {throw new RuntimeException();});
static <T> Result<T> ok(T value)
Create a Result for a success.
Use this where you have a value that you want to place into the Result context.
final Result<Integer> okay = Result.ok(1);
static <T> Result<T> error(Throwable error)
Create a Result for an error.
final Result<Integer> error = Result.error(new RuntimeException());
Static Methods
These static methods provide integration with the Maybe
class.
static <T> Maybe<T> toMaybe(Result<T> result)
Creates a Maybe
from the Result
, where the Result
is a success, then
the Maybe
will contain the value. However, if the Result
is an error
then the Maybe
will be nothing.
final Result<Integer> result = Result.of(() -> getValue());
final Maybe<Integer> maybe = Result.toMaybe(result);
static <T> Result<T> fromMaybe(Maybe<T> maybe, Supplier<Throwable> error)
Creates a Result
from the Maybe
, where the Result
will be an error
if the Maybe
is nothing. Where the Maybe
is nothing, then the
Supplier<Throwable>
will provide the error for the Result
.
final Maybe<Integer> maybe = Maybe.maybe(getValue());
final Result<Integer> result = Result.fromMaybe(maybe, () -> new NoSuchFileException("filename"));
static <T> Result<Maybe<T>> invert(Maybe<Result<T>> maybeResult)
Swaps the Result
within a Maybe
, so that Result
contains a Maybe
.
final Maybe<Result<Integer>> maybe = Maybe.maybe(Result.of(() -> getValue()));
final Result<Maybe<Integer>> result = Result.invert(maybe);
static <T,R> Result<Maybe<R>> flatMapMaybe(Result<Maybe<T>> maybeResult, Function<Maybe<T>,Result<Maybe<R>>> f)
Applies the function to the contents of a Maybe within the Result.
final Result<Maybe<Integer>> result = Result.of(() -> Maybe.maybe(getValue()));
final Result<Maybe<Integer>> maybeResult = Result.flatMapMaybe(result, maybe -> Result.of(() -> maybe.map(v -> v * 2)));
Instance Methods
<R> Result<R> map(Function<T,R> f)
Applies the function to the value within the Functor, returning the result within a Functor.
final Result<String> result = Result.of(() -> getValue())
.map(v -> String.valueOf(v));
<R> Result<R> flatMap(Function<T,Result<R>> f)
Returns a new Result consisting of the result of applying the function to the contents of the Result.
final Result<String> result = Result.of(() -> getValue())
.flatMap(v -> Result.of(() -> String.valueOf(v)));
<R> Result<R> andThen(Function<T,Callable<R>> f)
Maps a Success Result to another Result using a Callable that is able to throw a checked exception.
final Result<String> result = Result.of(() -> getValue())
.andThen(v -> () -> {throw new IOException();});
void match(Consumer<T> onSuccess, Consumer<Throwable> onError)
Matches the Result, either success or error, and supplies the appropriate Consumer with the value or error.
Result.of(() -> getValue())
.match(
success -> System.out.println(success),
error -> System.err.println("error")
);
Result<T> recover(Function<Throwable,Result<T>> f)
Provide a way to attempt to recover from an error state.
final Result<Integer> result = Result.of(() -> getValue())
.recover(e -> Result.of(() -> getSafeValue(e)));
Result<T> peek(Consumer<T> consumer)
Provide the value within the Result, if it is a success, to the Consumer, and returns this Result.
final Result<Integer> result = Result.of(() -> getValue())
.peek(v -> System.out.println(v));
Result<T> thenWith(Function<T,WithResultContinuation<T>> f)
Perform the continuation with the current Result value then return the current Result, assuming there was no error in the continuation.
final Result<Integer> result = Result.of(() -> getValue())
.thenWith(v -> () -> System.out.println(v))
.thenWith(v -> () -> {throw new IOException();});
Result<Maybe<T>> maybe(Predicate<T> predicate)
Wraps the value within the Result in a Maybe, either a Just if the predicate is true, or Nothing.
final Result<Maybe<Integer>> result = Result.of(() -> getValue())
.maybe(v -> v % 2 == 0);
T orElseThrow()
Extracts the successful value from the result, or throws the error
within a CheckedErrorResultException
.
final Integer result = Result.of(() -> getValue())
.orElseThrow();
<E extends Exception> T orElseThrow(Class<E> type) throws E
Extracts the successful value from the result, or throws the error when it
is of the given type. Any other errors will be thrown inside an
UnexpectedErrorResultException
.
final Integer result = Result.of(() -> getValue())
.orElseThrow(IOException.class);
T orElseThrowUnchecked()
Extracts the successful value from the result, or throws the error within
an ErrorResultException
.
final Integer result = Result.of(() -> getValue())
.orElseThrowUnchecked();
void onError(Consumer<Throwable> errorConsumer)
A handler for error states.
Result.of(() -> getValue())
.onError(e -> handleError(e));
boolean isOkay()
Checks if the Result is a success.
final boolean isOkay = Result.of(() -> getValue())
.isOkay();
boolean isError()
Checks if the Result is an error.
final boolean isError = Result.of(() -> getValue())
.isError();
Tree
A Generalised tree, where each node may or may not have an item, and may have any number of sub-trees. Leaf nodes are Trees with zero sub-trees.
Static Constructors
static <R> Tree<R> leaf(R item)
Create a leaf containing the item. The leaf has no sub-trees.
final Tree<String> tree = Tree.leaf("item");
static<R> Tree<R> of(R item, Collection<Tree<R>> subtrees)
Create a tree containing the item and sub-trees.
final Tree<String> tree = Tree.of("item", Collections.singletonList(Tree.leaf("leaf"));
static <B> TreeBuilder<B> builder(final Class<B> type)
Create a new TreeBuilder starting with an empty tree.
final TreeBuilder<Integer> builder = Tree.builder(Integer.class);
static <B> TreeBuilder<B> builder(final Tree<B> tree)
Create a new TreeBuilder for the given tree.
final Tree<Integer> tree = ...;
final TreeBuilder<Integer> builder = Tree.builder(tree);
Instance Methods
<R> Tree<R> map(Function<T, R> f)
Applies the function to the item within the Tree and to all sub-trees, returning a new Tree.
final Tree<UUID> tree = ...;
final Tree<String> result = tree.map(UUID::toString);
Maybe<T> item()
Returns the contents of the Tree node within a Maybe.
final Tree<Item> tree = ...;
final Maybe<Item> result = tree.item();
int count()
Returns the total number of items in the tree, including sub-trees. Null items don't count.
final Tree<Item> tree = ...;
final int result = tree.count();
List<Tree<T> subTrees()
Returns a list of sub-trees within the tree.
final Tree<Item> tree = ...;
final List<Tree<Item>> result = tree.subTrees();
TreeBuilder
A mutable builder for a Tree. Each TreeBuilder allows modification of a
single Tree node. You can use the select(childItem)
method to get a
TreeBuilder for the subtree that has the given child item.
final TreeBuilder<Integer> builder = Tree.builder();
builder.set(12).addChildren(Arrays.asList(1, 3, 5, 7));
final TreeBuilder<Integer> builderFor3 = builder.select(3);
builderFor3.addChildren(Arrays.asList(2, 4));
final Tree<Integer> tree = builder.build();
Will produce a tree like:
Static Constructors
None. The TreeBuilder is instantiated by Tree.builder()
.
Instance Methods
Tree<T> build()
Create the immutable Tree.
final TreeBuilder<Integer> builder = Tree.builder();
final Tree<Integer> tree = builder.build();
TreeBuilder<T> item(T item)
Set the current Tree's item and return the TreeBuilder.
TreeBuilder<T> add(Tree<T> subtree)
Adds the subtree to the current tree.
TreeBuilder<T> addChild(T childItem)
Add the Child item as a sub-Tree.
TreeBuilder<T> addChildren(List<T> children)
Add all the child items as subTrees.
Maybe<TreeBuilder<T>> select(T childItem)
Create a TreeBuilder for the subTree of the current Tree that has the childItem.
Lazy
A Lazy evaluated expression. Using a Supplier to provide the value, only evaluates the value when required, and never more than once.
Static Constructors
static <R> Lazy<R> of(Supplier<R> supplier)
Create a new Lazy value from the supplier.
final Suppler<UUID> supplier = ...;
final Lazy<UUID> lazy = Lazy.of(supplier);
Instance Methods
boolean isEvaluated()
Checks if the value has been evaluated.
final Lazy<UUID> lazy = ...;
final boolean isEvaluated = lazy.isEvaluated();
T value()
The value, evaluating it if necessary.
final Lazy<UUID> lazy = ...;
final UUID value = lazy.value();
<R> Lazy<R> map(Function<T, R> f)
Maps the Lazy instance into a new Lazy instance using the function.
final Lazy<UUID> uuidLazy = ...;
final Lazy<String> stringLazy = uuidLazy.map(v -> v.toString());
Either
Allows handling a value that can be one of two types, a left value/type or a right value/type.
When an Either
is returned from a method it will contain either a left or a
right.
Where the Either
is used to represent success/failure, the left case is, by
convention, used to indicate the error, and right the success. An alternative
is to use the Result
which more clearly distinguishes success from failure.
Either
is not a Monad.
Static Constructors
static <L, R> Either<L, R> left(final L l)
Create a new Either holding a left value.
final Either<Integer, String> left = Either.left(getIntegerValue());
static <L, R> Either<L, R> right(final R r)
Create a new Either holding a right value.
final Either<Integer, String> right = Either.right(getStringValue());
Instance Methods
boolean isLeft()
Checks if the Either holds a left value.
final boolean leftIsLeft = Either.<Integer, String>left(getIntegerValue()).isLeft();
final boolean rightIsLeft = Either.<Integer, String>right(getStringValue()).isLeft();
boolean isRight()
Checks if the Either holds a right value.
final boolean leftIsRight = Either.<Integer, String>left(getIntegerValue()).isRight();
final boolean rightIsRight = Either.<Integer, String>right(getStringValue()).isRight();
void match(Consumer<L> onLeft, Consumer<R> onRight)
Matches the Either, invoking the correct Consumer.
Either.<Integer, String>left(getIntegerValue())
.match(
left -> handleIntegerValue(left),
right -> handleStringValue(right)
);
<T> Either<T, R> mapLeft(Function<L, T> f)
Map the function across the left value.
final Either<Double, String> either = Either.<Integer, String>left(getIntegerValue())
.mapLeft(i -> i.doubleValue());
<T> Either<L, T> mapRight(Function<R, T> f)
Map the function across the right value.
final Either<Integer, String> either = Either.<Integer, String>left(getIntegerValue())
.mapRight(s -> s + "x");
<T> Either<T, R> flatMapLeft(Function<L, Either<T, R>> f)
FlatMap the function across the left value.
#+being_src java Either<Integer, String> either = Either.left(2); Either<Integer, String> resultLeft = either.flatMapLeft(l -> Either.left(l * 2)); Either<Integer, String> resultRight = either.flatMapLeft(l -> Either.right(l * 2));
#+end_src
<T> Either<T, R> flatMapRight(Function<L, Either<T, R>> f)
FlatMap the function across the right value.
#+being_src java Either<Integer, String> either = Either.right("2"); Either<Integer, String> resultLeft = either.flatMapRight(l -> Either.left(l * 2)); Either<Integer, String> resultRight = either.flatMapRight(l -> Either.right(l * 2));
#+end_src
Optional<L> getLeft()
Returns an Optional containing the left value, if is a left, otherwise returns an empty Optional.
#+being_src java Either<Integer, String> either = Either.right("2"); Optional<Integer> left = either.getLeft();
#+end_src
Optional<R> getRight()
Returns an Optional containing the right value, if is a right, otherwise returns an empty Optional.
#+being_src java Either<Integer, String> either = Either.right("2"); Optional<String> right = either.getRight();
#+end_src