{@link Left} and {@link Right} values cannot hold {@code null}. The {@link Empty} type could be used instead.
+ *
Right-biased; methods not ending in {@code Left} operate on {@link Right} values.
+ * However, the {@code xxxLeft} methods are provided so that a {@link #swap}() is not required.
+ *
Sealed; can be used in {@code switch} statements and deconstruction patterns.
+ *
Separable; this file only depends on standard JDK classes.
+ *
+ *
+ * For example:
+ * {@snippet :
+ * //** TODO ** include a succinct example
+ *}
*
*
- * (todo: explanation of right-bias)
+ * NOTE: For methods which accept or return type parameters {@code } or {@code },
+ * the {@code } or {@code } parameters can be completely different types from {@code } or {@code }.
*
* @param The left-hand value (by convention, this is the failure/unsuccessful value)
* @param The right-hand value (by convention, the success value)
*/
-// opinionated : no null for L or R; cannot use null (Void types not allowed; use 'None' instead)
-// sealed: can use in switch()
-// biased: right (typically error value in left) HOWEVER we do have xxxErr methods to operate on the left side
-// separable: everythign is defined in a single file.
-
-public sealed interface Either permits Either.Left, Either.Right {
+public sealed interface Either {
/**
* Create a Left {@link Either}.
@@ -63,27 +71,13 @@ static Either ofRight(@NotNull R value) {
* If the {@link Either} is {@link Left}, return the value as an {@link Optional}.
* Otherwise, return an empty {@link Optional}.
*/
- @NotNull
- default Optional left() {
- return switch (this) {
- case Left(L l) -> Optional.of( l );
- case Right(var __) -> Optional.empty();
- };
- }
+ @NotNull Optional left();
/**
* If the {@link Either} is {@link Right}, return the value as an {@link Optional}.
* Otherwise, return an empty {@link Optional}.
*/
- @NotNull
- default Optional right() {
- return switch (this) {
- case Right(R r) -> Optional.of( r );
- case Left(var __) -> Optional.empty();
- };
- }
-
-
+ @NotNull Optional right();
/**
@@ -95,19 +89,7 @@ default Optional right() {
* @see #match(Consumer)
* @see #matchLeft(Consumer)
*/
- @NotNull
- default Either biMatch(@NotNull Consumer super L> leftConsumer,
- @NotNull Consumer super R> rightConsumer) {
- requireNonNull( leftConsumer );
- requireNonNull( rightConsumer );
-
- switch (this) {
- case Left(L l) -> leftConsumer.accept( l );
- case Right(R r) -> rightConsumer.accept( r );
- }
-
- return this;
- }
+ @NotNull Either biMatch(@NotNull Consumer super L> leftConsumer, @NotNull Consumer super R> rightConsumer);
/**
@@ -123,17 +105,7 @@ default Either biMatch(@NotNull Consumer super L> leftConsumer,
* @see #map(Function)
* @see #mapLeft(Function)
*/
- @NotNull
- default Either biMap(@NotNull Function super L, ? extends L2> fnLeft,
- @NotNull Function super R, ? extends R2> fnRight) {
- requireNonNull( fnLeft );
- requireNonNull( fnRight );
-
- return switch (this) {
- case Left(L l) -> ofLeft( fnLeft.apply( l ) );
- case Right(R r) -> ofRight( fnRight.apply( r ) );
- };
- }
+ @NotNull Either biMap(@NotNull Function super L, ? extends L2> fnLeft, @NotNull Function super R, ? extends R2> fnRight);
/**
@@ -151,18 +123,7 @@ default Either biMap(@NotNull Function super L, ? extends L2>
* @see #map(Function)
* @see #mapLeft(Function)
*/
- @NotNull
- @SuppressWarnings("unchecked")
- default Either biFlatMap(@NotNull Function super L, ? extends Either extends L2, ? extends R2>> fnLeft,
- @NotNull Function super R, ? extends Either extends L2, ? extends R2>> fnRight) {
- requireNonNull( fnLeft );
- requireNonNull( fnRight );
-
- return switch (this) {
- case Left(L l) -> (Either) requireNonNull( fnLeft.apply( l ) );
- case Right(R r) -> (Either) requireNonNull( fnRight.apply( r ) );
- };
- }
+ @NotNull Either biFlatMap(@NotNull Function super L, ? extends Either extends L2, ? extends R2>> fnLeft, @NotNull Function super R, ? extends Either extends L2, ? extends R2>> fnRight);
/**
@@ -183,18 +144,7 @@ default Either biFlatMap(@NotNull Function super L, ? extends
* @see #recover(Function)
* @see #forfeit(Function)
*/
- @NotNull
- default T fold(@NotNull Function super L, ? extends T> fnLeft,
- @NotNull Function super R, ? extends T> fnRight) {
- requireNonNull( fnLeft );
- requireNonNull( fnRight );
-
- return switch (this) {
- case Left(L l) -> requireNonNull( fnLeft.apply( l ) );
- case Right(R r) -> requireNonNull( fnRight.apply( r ) );
-
- };
- }
+ @NotNull T fold(@NotNull Function super L, ? extends T> fnLeft, @NotNull Function super R, ? extends T> fnRight);
/**
@@ -214,19 +164,7 @@ default T fold(@NotNull Function super L, ? extends T> fnLeft,
* @return an {@link Either} based on the algorithm described above.
* @throws NullPointerException if the called mapping function returns {@code null}.
*/
- @NotNull
- default Either filter(@NotNull Predicate super R> predicate,
- @NotNull Function super R, ? extends L> mapper) {
- requireNonNull( predicate );
- requireNonNull( mapper );
-
- return switch (this) {
- case Left(L l) -> this;
- case Right(R r) -> predicate.test( r )
- ? this
- : Either.ofLeft( mapper.apply( r ) ); // implicit null check
- };
- }
+ @NotNull Either filter(@NotNull Predicate super R> predicate, @NotNull Function super R, ? extends L> mapper);
/**
@@ -243,10 +181,7 @@ case Right(R r) -> predicate.test( r )
* @throws NullPointerException if the result of the mapping function is {@code null}.
* @see #recover(Function)
*/
- @NotNull
- default L forfeit(@NotNull Function super R, ? extends L> fn) {
- return fold( Function.identity(), fn );
- }
+ @NotNull L forfeit(@NotNull Function super R, ? extends L> fn);
/**
@@ -264,10 +199,7 @@ default L forfeit(@NotNull Function super R, ? extends L> fn) {
* @throws NullPointerException if the result of the mapping function is {@code null}.
* @see #forfeit(Function)
*/
- @NotNull
- default R recover(@NotNull Function super L, ? extends R> fn) {
- return fold( fn, Function.identity() );
- }
+ @NotNull R recover(@NotNull Function super L, ? extends R> fn);
/**
@@ -277,13 +209,7 @@ default R recover(@NotNull Function super L, ? extends R> fn) {
* @return Stream
* @see #streamLeft()
*/
- @NotNull
- default Stream stream() {
- return switch (this) {
- case Left(L l) -> Stream.empty();
- case Right(R r) -> Stream.of( r );
- };
- }
+ @NotNull Stream stream();
/**
* Return a {@link Stream}, containing either a single {@link Left} value, or an empty {@link Stream}
@@ -291,13 +217,7 @@ default Stream stream() {
*
* @see #stream()
*/
- @NotNull
- default Stream streamLeft() {
- return switch (this) {
- case Left(L l) -> Stream.of( l );
- case Right(R r) -> Stream.empty();
- };
- }
+ @NotNull Stream streamLeft();
/**
* Determines if this {@link Right} {@link Either} contains the given value.
@@ -307,16 +227,11 @@ default Stream streamLeft() {
*
* @param rVal value to compare
* @return {@code true} iff this is a {@link Right} {@link Either} and the contained value equals {@code rVal}
- * @see #matches
+ * @see #ifPredicate
* @see #containsLeft
- * @see #matchesLeft
+ * @see #ifPredicateLeft
*/
- default boolean contains(@Nullable R rVal) {
- return switch (this) {
- case Left(L l) -> false;
- case Right(R r) -> r.equals( rVal );
- };
- }
+ boolean contains(@Nullable R rVal);
/**
* Determines if this {@link Left} {@link Either} contains the given value.
@@ -326,16 +241,11 @@ default boolean contains(@Nullable R rVal) {
*
* @param lVal value to compare
* @return {@code true} iff this is a {@link Left} {@link Either} and the contained value equals {@code lVal}
- * @see #matchesLeft
- * @see #matches
+ * @see #ifPredicateLeft
+ * @see #ifPredicate
* @see #contains
*/
- default boolean containsLeft(@Nullable L lVal) {
- return switch (this) {
- case Left(L l) -> l.equals( lVal );
- case Right(R r) -> false;
- };
- }
+ boolean containsLeft(@Nullable L lVal);
/**
* Determines if this {@link Right} {@link Either} matches the given {@link Predicate}.
@@ -346,17 +256,10 @@ default boolean containsLeft(@Nullable L lVal) {
* @param rp the {@link Predicate} to test
* @return {@code true} iff this is a {@link Right} {@link Either} and the {@link Predicate} matches.
* @see #contains
- * @see #matchesLeft
+ * @see #ifPredicateLeft
* @see #containsLeft
*/
- default boolean matches(@NotNull Predicate rp) {
- requireNonNull( rp );
-
- return switch (this) {
- case Left(L l) -> false;
- case Right(R r) -> rp.test( r );
- };
- }
+ boolean ifPredicate(@NotNull Predicate rp);
/**
* Determines if this {@link Left} {@link Either} matches the given {@link Predicate}.
@@ -368,16 +271,9 @@ default boolean matches(@NotNull Predicate rp) {
* @return {@code true} iff this is a {@link Left} {@link Either} and the {@link Predicate} matches.
* @see #containsLeft
* @see #contains
- * @see #matches
+ * @see #ifPredicate
*/
- default boolean matchesLeft(@NotNull Predicate lp) {
- requireNonNull( lp );
-
- return switch (this) {
- case Left(L l) -> lp.test( l );
- case Right(R r) -> false;
- };
- }
+ boolean ifPredicateLeft(@NotNull Predicate lp);
/**
* If this is a {@link Right}, return a new {@link Right} value produced by the given mapping function.
@@ -397,10 +293,7 @@ default boolean matchesLeft(@NotNull Predicate lp) {
* @see #mapLeft(Function)
* @see #biMap(Function, Function)
*/
- @NotNull
- default Either map(@NotNull Function super R, ? extends R2> rightMapper) {
- return biMap( Function.identity(), rightMapper );
- }
+ @NotNull Either map(@NotNull Function super R, ? extends R2> rightMapper);
/**
* If this is a {@link Right}, return the new {@link Either} supplied by the mapping function.
@@ -420,17 +313,7 @@ default Either map(@NotNull Function super R, ? extends R2> rightM
* @see #biFlatMap(Function, Function)
* @see #flatMapLeft(Function)
*/
- @SuppressWarnings("unchecked")
- @NotNull
- default Either flatMap(@NotNull Function super R, ? extends
- Either extends L, ? extends R2>> rightMapper) {
- requireNonNull( rightMapper );
-
- return switch (this) {
- case Left(L l) -> (Left) this; // coerce right
- case Right(R r) -> (Either) requireNonNull( rightMapper.apply( r ) );
- };
- }
+ @NotNull Either flatMap(@NotNull Function super R, ? extends Either extends L, ? extends R2>> rightMapper);
/**
@@ -451,10 +334,8 @@ default Either flatMap(@NotNull Function super R, ? extends
* @see #map(Function)
* @see #biMap(Function, Function)
*/
- @NotNull
- default Either mapLeft(@NotNull Function super L, ? extends L2> leftMapper) {
- return biMap( leftMapper, Function.identity() );
- }
+ @NotNull Either mapLeft(@NotNull Function super L, ? extends L2> leftMapper);
+
/**
* If this is a {@link Left}, return the new {@link Either} supplied by the mapping function.
@@ -474,45 +355,42 @@ default Either mapLeft(@NotNull Function super L, ? extends L2> le
* @see #biFlatMap(Function, Function)
* @see #flatMap(Function)
*/
- @SuppressWarnings("unchecked")
- @NotNull
- default Either flatMapLeft(@NotNull Function super L, ? extends
- Either extends L2, ? extends R>> leftMapper) {
- requireNonNull( leftMapper );
-
- return switch (this) {
- case Left(L l) -> (Either) requireNonNull( leftMapper.apply( l ) );
- case Right(R r) -> (Right) this; // coerce left
- };
- }
+ @NotNull Either flatMapLeft(@NotNull Function super L, ? extends Either extends L2, ? extends R>> leftMapper);
/**
* Executes the action iff this is a {@link Left} {@link Either}.
*
* @return {@code this}
+ * @param leftConsumer the consumer function to be executed
* @throws NullPointerException if the called action returns {@code null}.
* @see #match(Consumer)
* @see #biMatch(Consumer, Consumer)
*/
- @NotNull
- default Either matchLeft(@NotNull Consumer super L> leftConsumer) {
- return biMatch( leftConsumer, (x) -> {} );
- }
+ @NotNull Either matchLeft(@NotNull Consumer super L> leftConsumer);
/**
* Executes the action iff this is a {@link Right} {@link Either}.
*
* @return {@code this}
+ * @param rightConsumer the consumer function to be executed
* @throws NullPointerException if the called action returns {@code null}.
* @see #match(Consumer)
* @see #biMatch(Consumer, Consumer)
*/
- @NotNull
- default Either match(@NotNull Consumer super R> rightConsumer) {
- return biMatch( (x) -> {}, rightConsumer );
+ @NotNull Either match(@NotNull Consumer super R> rightConsumer);
+
+
+ /**
+ * Executes the given consumer if this is a {@link Right}. This is a terminal operation.
+ *
+ * @param rightConsumer the consumer function to be executed
+ */
+ default void consume(@NotNull Consumer super R> rightConsumer) {
+ match(rightConsumer);
}
+
/**
* If this {@link Either} is {@link Left}, return {@code rightAlternate}.
* Otherwise, return {@code this} (a {@link Right} {@link Either}).
@@ -523,15 +401,7 @@ default Either match(@NotNull Consumer super R> rightConsumer) {
* @see #orElseLeft
* @see #orElseGetLeft
*/
- @NotNull
- default R orElse(@NotNull R rightAlternate) {
- requireNonNull( rightAlternate );
-
- return switch (this) {
- case Left(L l) -> rightAlternate;
- case Right(R r) -> r;
- };
- }
+ @NotNull R orElse(@NotNull R rightAlternate);
/**
* If this {@link Either} is {@link Right}, return {@code leftAlternate}.
@@ -543,14 +413,7 @@ default R orElse(@NotNull R rightAlternate) {
* @see #orElse
* @see #orElseGet
*/
- @NotNull
- default L orElseLeft(@NotNull L leftAlternate) {
- requireNonNull( leftAlternate );
- return switch (this) {
- case Left(L l) -> l;
- case Right(R r) -> leftAlternate;
- };
- }
+ @NotNull L orElseLeft(@NotNull L leftAlternate);
/**
* If this {@link Either} is {@link Left}, return the supplied {@link Right} {@link Either}.
@@ -563,15 +426,7 @@ default L orElseLeft(@NotNull L leftAlternate) {
* @see #orElseLeft
* @see #orElseGetLeft
*/
- @NotNull
- default R orElseGet(@NotNull Supplier extends R> rightSupplier) {
- requireNonNull( rightSupplier );
-
- return switch (this) {
- case Left(L l) -> rightSupplier.get();
- case Right(R r) -> r;
- };
- }
+ @NotNull R orElseGet(@NotNull Supplier extends R> rightSupplier);
/**
* If this {@link Either} is {@link Right}, return the supplied {@link Left} {@link Either}.
@@ -584,15 +439,7 @@ default R orElseGet(@NotNull Supplier extends R> rightSupplier) {
* @see #orElse
* @see #orElseGet
*/
- @NotNull
- default L orElseGetLeft(@NotNull Supplier extends L> leftSupplier) {
- requireNonNull( leftSupplier );
-
- return switch (this) {
- case Left(L l) -> l;
- case Right(R r) -> leftSupplier.get();
- };
- }
+ @NotNull L orElseGetLeft(@NotNull Supplier extends L> leftSupplier);
/**
@@ -604,15 +451,7 @@ default L orElseGetLeft(@NotNull Supplier extends L> leftSupplier) {
* @see #or(Either)
* @see #or(Supplier)
*/
- @NotNull
- default Either and(@NotNull Either nextEither) {
- requireNonNull( nextEither );
-
- return switch (this) {
- case Left(L l) -> ((Left) this).coerce();
- case Right(R r) -> nextEither;
- };
- }
+ @NotNull Either and(@NotNull Either nextEither);
/**
* If {@code this} is {@link Left}, return it (without invoking the {@link Supplier}).
@@ -626,15 +465,7 @@ default Either and(@NotNull Either nextEither) {
* @see #or(Either)
* @see #or(Supplier)
*/
- @NotNull
- default Either and(@NotNull Supplier> nextEitherSupplier) {
- requireNonNull( nextEitherSupplier );
-
- return switch (this) {
- case Left(L l) -> ((Left) this).coerce();
- case Right(R r) -> requireNonNull( nextEitherSupplier.get() );
- };
- }
+ @NotNull Either and(@NotNull Supplier> nextEitherSupplier);
/**
@@ -648,15 +479,7 @@ default Either and(@NotNull Supplier> nextEitherSuppli
* @see #and(Either)
* @see #and(Supplier)
*/
- @NotNull
- default Either or(@NotNull Either nextEither) {
- requireNonNull( nextEither );
-
- return switch (this) {
- case Left(L l) -> nextEither;
- case Right(R r) -> ((Right) this).coerce();
- };
- }
+ @NotNull Either or(@NotNull Either nextEither);
/**
@@ -671,15 +494,7 @@ default Either or(@NotNull Either nextEither) {
* @see #and(Either)
* @see #and(Supplier)
*/
- @NotNull
- default Either or(@NotNull Supplier> nextEitherSupplier) {
- requireNonNull( nextEitherSupplier );
-
- return switch (this) {
- case Left(L l) -> requireNonNull( nextEitherSupplier.get() );
- case Right(R r) -> ((Right) this).coerce();
- };
- }
+ @NotNull Either or(@NotNull Supplier> nextEitherSupplier);
/**
@@ -696,15 +511,7 @@ default Either or(@NotNull Supplier> nextEitherSupplie
* @throws X the supplied {@link Exception}
* @throws NullPointerException if the called Supplier returns {@code null}.
*/
- @NotNull
- default R getOrThrow(@NotNull Supplier supplier) throws X {
- requireNonNull( supplier );
-
- return switch (this) {
- case Left(L l) -> throw supplier.get();
- case Right(R r) -> r;
- };
- }
+ @NotNull R expect(@NotNull Supplier supplier) throws X;
/**
@@ -754,15 +561,7 @@ default R getOrThrow(@NotNull Supplier supplier) throws
* @throws X the produced {@link Exception}
* @throws NullPointerException if the called Function returns {@code null}.
*/
- @NotNull
- default R getOrThrowWrapped(@NotNull Function exFn) throws X {
- requireNonNull( exFn );
-
- return switch (this) {
- case Left(L l) -> throw exFn.apply( l );
- case Right(R r) -> r;
- };
- }
+ @NotNull R getOrThrow(@NotNull Function exFn) throws X;
/**
@@ -774,27 +573,21 @@ default R getOrThrowWrapped(@NotNull Function exFn)
* For example, the following are equivalent:
*
* {@snippet :
- * myEither.flatMapLeft(MyFunction::doit) == myEither.swap().flatMap(MyFunction::doit);
+ * myEither.flatMapLeft(MyFunction::doIt) == myEither.swap().flatMap(MyFunction::doIt);
*}
*
* @return A new {@link Either} with left and right values swapped.
*/
- default
- @NotNull Either swap() {
- // optimized; could use biFlatMap( Either::ofRight, Either::ofLeft );
- return switch (this) {
- case Left(L l) -> Either.ofRight( l );
- case Right(R r) -> Either.ofLeft( r );
- };
- }
+
+ @NotNull Either swap();
/**
* Implementation of a Left {@link Either}.
*
* @param value Left value. May not be {@code null}.
- * @param parameter type of Left values.
- * @param parameter type of Right values.
+ * @param parameter type of Left values.
+ * @param parameter type of Right values.
*/
record Left(@NotNull L value) implements Either {
@@ -811,19 +604,317 @@ record Left(@NotNull L value) implements Either {
* Get the value. Never null.
*/
@NotNull
- public L get() { return value; }
+ public L get() {return value;}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Optional left() {
+ return Optional.of( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Optional right() {
+ return Optional.empty();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either biMatch(@NotNull Consumer super L> leftConsumer, @NotNull Consumer super R> rightConsumer) {
+ requireNonNull( leftConsumer );
+ requireNonNull( rightConsumer );
+ leftConsumer.accept( value );
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either biMap(@NotNull Function super L, ? extends L2> fnLeft, @NotNull Function super R, ? extends R2> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return Either.ofLeft( fnLeft.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public @NotNull Either biFlatMap(@NotNull Function super L, ? extends Either extends L2, ? extends R2>> fnLeft, @NotNull Function super R, ? extends Either extends L2, ? extends R2>> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return (Either) requireNonNull( fnLeft.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull T fold(@NotNull Function super L, ? extends T> fnLeft, @NotNull Function super R, ? extends T> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return requireNonNull( fnLeft.apply( value ) );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either filter(@NotNull Predicate super R> predicate, @NotNull Function super R, ? extends L> mapper) {
+ requireNonNull( predicate );
+ requireNonNull( mapper );
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Stream stream() {
+ return Stream.empty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Stream streamLeft() {
+ return Stream.of( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean contains(@Nullable R rVal) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsLeft(@Nullable L lVal) {
+ return value.equals( lVal );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean ifPredicate(@NotNull Predicate rp) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean ifPredicateLeft(@NotNull Predicate lp) {
+ return requireNonNull( lp ).test( value );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public @NotNull Either flatMapLeft(@NotNull Function super L, ? extends Either extends L2, ? extends R>> leftMapper) {
+ requireNonNull( leftMapper );
+ return (Either) requireNonNull( leftMapper.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either flatMap(@NotNull Function super R, ? extends Either extends L, ? extends R2>> rightMapper) {
+ requireNonNull( rightMapper );
+ return coerce();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R orElse(@NotNull R rightAlternate) {
+ requireNonNull( rightAlternate );
+ return rightAlternate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L orElseLeft(@NotNull L leftAlternate) {
+ requireNonNull( leftAlternate );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R orElseGet(@NotNull Supplier extends R> rightSupplier) {
+ requireNonNull( rightSupplier );
+ return requireNonNull( rightSupplier.get() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L orElseGetLeft(@NotNull Supplier extends L> leftSupplier) {
+ requireNonNull( leftSupplier );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L forfeit(@NotNull Function super R, ? extends L> fn) {
+ requireNonNull( fn );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R recover(@NotNull Function super L, ? extends R> fn) {
+ requireNonNull( fn );
+ return requireNonNull( fn.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either map(@NotNull Function super R, ? extends R2> rightMapper) {
+ requireNonNull( rightMapper );
+ return coerce();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public @NotNull Either mapLeft(@NotNull Function super L, ? extends L2> leftMapper) {
+ requireNonNull( leftMapper );
+ return (Either) Either.ofLeft( leftMapper.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either matchLeft(@NotNull Consumer super L> leftConsumer) {
+ requireNonNull( leftConsumer );
+ leftConsumer.accept( value );
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either match(@NotNull Consumer super R> rightConsumer) {
+ requireNonNull( rightConsumer );
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either or(@NotNull Supplier> nextEitherSupplier) {
+ requireNonNull( nextEitherSupplier );
+ return requireNonNull( nextEitherSupplier.get() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either swap() {
+ return Either.ofRight( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either and(@NotNull Either nextEither) {
+ requireNonNull( nextEither );
+ return coerce();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // more efficient than implementation : does not invoke supplier
+ @Override
+ public @NotNull Either and(@NotNull Supplier> nextEitherSupplier) {
+ requireNonNull( nextEitherSupplier );
+ return coerce();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either or(@NotNull Either nextEither) {
+ requireNonNull( nextEither );
+ return nextEither;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R expect(@NotNull Supplier supplier) throws X {
+ requireNonNull( supplier );
+ throw requireNonNull( supplier.get() );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R getOrThrow(@NotNull Function exFn) throws X {
+ requireNonNull( exFn );
+ throw requireNonNull( exFn.apply( value ) );
+ }
+
/**
* Coerce the empty Right parameter to the new type.
*
- * Does not create a new object.
+ * Does not create a new object.
*
*
- * @return coerced Left
* @param new Right parameter
- */ @SuppressWarnings("unchecked")
+ * @return coerced Left
+ */
+ @SuppressWarnings("unchecked")
@NotNull
- public Either coerce() {
+ private Either coerce() {
return (Either) this;
}
}
@@ -849,21 +940,321 @@ record Right(@NotNull R value) implements Either {
* Get the value. Never null.
*/
@NotNull
- public R get() { return value; }
+ public R get() {return value;}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Optional left() {
+ return Optional.empty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Optional right() {
+ return Optional.of( value );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either biMatch(@NotNull Consumer super L> leftConsumer, @NotNull Consumer super R> rightConsumer) {
+ requireNonNull( leftConsumer );
+ requireNonNull( rightConsumer );
+ rightConsumer.accept( value );
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either biMap(@NotNull Function super L, ? extends L2> fnLeft, @NotNull Function super R, ? extends R2> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return Either.ofRight( fnRight.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public @NotNull Either biFlatMap(@NotNull Function super L, ? extends Either extends L2, ? extends R2>> fnLeft, @NotNull Function super R, ? extends Either extends L2, ? extends R2>> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return (Either) requireNonNull( fnRight.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull T fold(@NotNull Function super L, ? extends T> fnLeft, @NotNull Function super R, ? extends T> fnRight) {
+ requireNonNull( fnLeft );
+ requireNonNull( fnRight );
+ return requireNonNull( fnRight.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either filter(@NotNull Predicate super R> predicate, @NotNull Function super R, ? extends L> mapper) {
+ requireNonNull( predicate );
+ requireNonNull( mapper );
+ return predicate.test( value ) ? this : Either.ofLeft( mapper.apply( value ) ); // implicit null check
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Stream stream() {
+ return Stream.of( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Stream streamLeft() {
+ return Stream.empty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean contains(@Nullable R rVal) {
+ return value.equals( rVal );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsLeft(@Nullable L lVal) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean ifPredicate(@NotNull Predicate rp) {
+ return requireNonNull( rp ).test( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean ifPredicateLeft(@NotNull Predicate lp) {
+ requireNonNull( lp );
+ return false;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either flatMapLeft(@NotNull Function super L, ? extends Either extends L2, ? extends R>> leftMapper) {
+ requireNonNull( leftMapper );
+ return coerce();
+ }
+
+ @SuppressWarnings("unchecked")
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either flatMap(@NotNull Function super R, ? extends Either extends L, ? extends R2>> rightMapper) {
+ requireNonNull( rightMapper );
+ return (Either) requireNonNull( rightMapper.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R orElse(@NotNull R rightAlternate) {
+ requireNonNull( rightAlternate );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L orElseLeft(@NotNull L leftAlternate) {
+ requireNonNull( leftAlternate );
+ return leftAlternate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R orElseGet(@NotNull Supplier extends R> rightSupplier) {
+ requireNonNull( rightSupplier );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L orElseGetLeft(@NotNull Supplier extends L> leftSupplier) {
+ requireNonNull( leftSupplier );
+ return requireNonNull( leftSupplier.get() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either and(@NotNull Either nextEither) {
+ requireNonNull( nextEither );
+ return nextEither;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either or(@NotNull Either nextEither) {
+ requireNonNull( nextEither );
+ return coerce();
+ }
+
+ // more efficient than implementation : does not invoke supplier
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either or(@NotNull Supplier> nextEitherSupplier) {
+ requireNonNull( nextEitherSupplier );
+ return coerce();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull L forfeit(@NotNull Function super R, ? extends L> fn) {
+ requireNonNull( fn );
+ return requireNonNull( fn.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R recover(@NotNull Function super L, ? extends R> fn) {
+ requireNonNull( fn );
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either map(@NotNull Function super R, ? extends R2> rightMapper) {
+ requireNonNull( rightMapper );
+ return Either.ofRight( rightMapper.apply( value ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either mapLeft(@NotNull Function super L, ? extends L2> leftMapper) {
+ requireNonNull( leftMapper );
+ return coerce();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either matchLeft(@NotNull Consumer super L> leftConsumer) {
+ requireNonNull( leftConsumer );
+ // do nothing
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either match(@NotNull Consumer super R> rightConsumer) {
+ requireNonNull( rightConsumer );
+ rightConsumer.accept( value );
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either and(@NotNull Supplier> nextEitherSupplier) {
+ requireNonNull( nextEitherSupplier );
+ return requireNonNull( nextEitherSupplier.get() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull Either swap() {
+ return ofLeft( value );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @NotNull
+ public R expect(@NotNull Supplier supplier) throws X {
+ // supplier not invoked
+ requireNonNull( supplier );
+ return value;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NotNull R getOrThrow(@NotNull Function exFn) {
+ // function not invoked
+ requireNonNull( exFn );
+ return value;
+ }
/**
* Coerce the empty Left parameter to the new type.
*
- * Does not create a new object.
+ * Does not create a new object.
*
*
- * @return coerced Right
* @param new Left parameter
+ * @return coerced Right
*/
@SuppressWarnings("unchecked")
@NotNull
- public Either coerce() {
+ private Either coerce() {
return (Either) this;
}
}
diff --git a/src/main/java/net/xyzsd/dichotomy/None.java b/src/main/java/net/xyzsd/dichotomy/Empty.java
similarity index 52%
rename from src/main/java/net/xyzsd/dichotomy/None.java
rename to src/main/java/net/xyzsd/dichotomy/Empty.java
index 9fbdec5..1f2e88b 100644
--- a/src/main/java/net/xyzsd/dichotomy/None.java
+++ b/src/main/java/net/xyzsd/dichotomy/Empty.java
@@ -7,7 +7,8 @@
* as it cannot be instantiated, and extensive null-checking is in place.
*
*
- * Instead, the {@link None} type can be used. All {@link None} types are considered equivalent.
+ * Instead, the {@link Empty} type can be used. All {@link Empty} types are considered equivalent.
*
*/
-public record None() {}
+public record Empty() {}
+// 'Empty' instead of None to differ from Maybe.None. 'Nil' could be a consideration. or maybe all caps to denote singleton ('NONE')
diff --git a/src/main/java/net/xyzsd/dichotomy/Maybe.java b/src/main/java/net/xyzsd/dichotomy/Maybe.java
index 2cf3f76..27230fe 100644
--- a/src/main/java/net/xyzsd/dichotomy/Maybe.java
+++ b/src/main/java/net/xyzsd/dichotomy/Maybe.java
@@ -14,186 +14,483 @@
import static java.util.Objects.requireNonNull;
-
-public sealed interface Maybe {
-
+/**
+ * A type which holds a value {@link Some}, or no value {@link None}.
+ *
+ * This is analogous to the standard {@link java.util.Optional} class, but this is a sealed
+ * type and can be used in {@code switch} statements and supports pattern-matching.
+ *
+ * @param Value type.
+ */
+public sealed interface Maybe {
+
+
+ /**
+ * Create a Maybe with the given non-null value.
+ *
+ * @param value value of this Maybe
+ * @param value type
+ * @return Maybe holding given value.
+ */
static Maybe of(@NotNull T value) {
return new Some<>( value );
}
+ /**
+ * Create an empty {@link Maybe}.
+ *
+ * @param value type
+ * @return empty Maybe
+ */
static Maybe ofNone() {
- return new None<>();
+ return None.empty();
}
+ /**
+ * Given a potentially nullable value, create a {@link Maybe} holding the value
+ * or an empty {@link Maybe} if the value is null.
+ *
+ * @param value value of this Maybe
+ * @param value type
+ * @return Maybe
+ */
static Maybe ofNullable(@Nullable T value) {
return (value == null) ? Maybe.ofNone() : Maybe.of( value );
}
-
+ /**
+ * Perform an action depending on whether the {@link Maybe} is a {@link Some} or a {@link None}.
+ *
+ * This is analagous to {@link java.util.Optional#ifPresentOrElse(Consumer, Runnable)}
+ *
+ * @param someConsumer action performed if {@link Some}
+ * @param noneRunner action performed if {@link None}
+ * @return this
+ */
+ @NotNull Maybe biMatch(@NotNull Consumer super T> someConsumer, @NotNull Runnable noneRunner);
+
+ /**
+ * Filter based on the given {@link Predicate}. If the Predicate is false, or this is a {@link None},
+ * a {@link None} value is returned.
+ *
+ * @param predicate {@link Predicate} to test.
+ * @return this or {@link None}
+ */
+ @NotNull Maybe filter(@NotNull Predicate super T> predicate);
+
+ /**
+ * Map a {@link Some} or {@link None} value to a given type.
+ *
+ * @param fnSome mapping function for Some values
+ * @param supNone supplier for None values
+ * @param return type of both functions
+ * @return result of one of the above mapping function or supplier.
+ */
+ @NotNull U fold(@NotNull Function super T, ? extends U> fnSome, @NotNull Supplier extends U> supNone);
+
+ /**
+ * Stream the value contained. The stream will consist of at most a single element, and
+ * will contain no elements if it is a {@link None}.
+ *
+ * @return Stream
+ */
+ @NotNull Stream stream();
+
+ /**
+ * Map {@link Some} types. No mapping is performed if the type is {@link None}.
+ *
+ * @param fnSome mapping function for {@link Some} values
+ * @param return type of function
+ * @return the result of the mapping function or a {@link None}
+ */
+ // only maps if present
+ @NotNull Maybe map(@NotNull Function super T, ? extends U> fnSome);
+
+ /**
+ * If the {@link Maybe} is a {@link Some}, call the provided {@link Consumer}. Otherwise, do nothing.
+ *
+ * @param someConsumer act upon the given {@link Some} value
+ * @return this
+ */
+ Maybe match(@NotNull Consumer super T> someConsumer);
+
+ /**
+ * If the {@link Maybe} is a {@link Some}, call the provided {@link Consumer}. Otherwise, do nothing.
+ *
+ * This is functionally equivalent to {@link #match(Consumer)} but does not return {@code this},
+ * clearly marking it as a terminal operation.
+ *
+ * @param someConsumer act upon the given {@link Some} value
+ */
+ void consume(@NotNull Consumer super T> someConsumer);
+
+ /**
+ * If a value is present ({@link Some}), return the result of applying the given mapping function to the value,
+ * otherwise returns a {@link None}.
+ *
+ * This does not wrap the returned function value in a new {@link Some} value, unlike {@link #map(Function)}.
+ *
+ * @param mapper mapper for {@link Some} values.
+ * @param type of {@link Maybe} returned.
+ * @return result of mapping, or {@link None}
+ */
+ @NotNull Maybe flatMap(@NotNull Function super T, ? extends Maybe extends U>> mapper);
+
+ /**
+ * Terminal operation which tests a {@link Some} value against the given {@link Predicate}.
+ *
+ * This is functionally equivalent to:
+ * {@snippet :
+ * filter(Predicate).hasSome()
+ * }
+ *
+ * @param predicate {@link Predicate} to test
+ * @return result of predicate testing
+ */
+ boolean matches(@NotNull Predicate predicate);
+
+ /**
+ * Returns {@code true} if {@code value} equals the value contained in a {@link Some}.
+ * If {@code value} is {@code null}, returns {@code true} if {@link None}.
+ *
+ * This is analogous to {@link java.util.Optional#equals(Object)}.
+ *
+ * @param value value to evaluate
+ * @return true if provided value equals the contained value.
+ */
+ boolean contains(@Nullable final T value);
+
+ /**
+ * True if this is a {@link Some}.
+ *
+ * @return {@code true} if this is a {@link Some} type.
+ */
+ boolean hasSome();
+
+ /**
+ * If this is a {@link Some}, return it. Otherwise, use the provided alternate value.
+ *
+ * @param alternate used if this is {@link None}
+ * @return value
+ */
+ @NotNull T orElse(@NotNull T alternate);
+
+ /**
+ * If this is a {@link Some}, return it. Otherwise, use the provided alternate value.
+ * The Supplier is only invoked if this is a {@link None}.
+ *
+ * @param supplier, used if this is {@link None}
+ * @return value
+ */
+ @NotNull T orElse(@NotNull Supplier extends T> supplier);
+
+ /**
+ * Get the next {@link Maybe}, but only if the current {@link Maybe} is a {@link Some}.
+ * Otherwise, do nothing.
+ *
+ * @param nextMaybe if this is not a {@link None}
+ * @param type of Maybe returned
+ */
+ @NotNull Maybe and(@NotNull Maybe extends U> nextMaybe);
+
+ /**
+ * Get the next {@link Maybe}, but only if the current {@link Maybe} is a {@link Some}.
+ * Otherwise, do nothing.
+ *
+ * @param nextMaybeSupplier invoked this is not a {@link None}
+ * @param type of Maybe returned
+ */
+ @NotNull Maybe and(@NotNull Supplier> nextMaybeSupplier);
+
+ /**
+ * If this is a {@link Some}, return it. Otherwise, return {@code nextMaybe}.
+ *
+ * @param nextMaybe (returned if this is a {@link None}
+ */
+ @NotNull Maybe or(@NotNull Maybe nextMaybe);
+
+ /**
+ * If this is a {@link Some}, return it. Otherwise, return the maybe via the provided {@link Supplier}.
+ *
+ * @param nextMaybeSupplier (invoked if this is a {@link None}
+ */
+ @NotNull Maybe or(@NotNull Supplier> nextMaybeSupplier);
+
+ /**
+ * Get the value, if this is a {@link Some}; otherwise, throw an exception.
+ *
+ * @return value
+ * @throws NoSuchElementException if this is a {@link None}
+ */
+ @NotNull T expect();
+
+ /**
+ * Get the value, if this is a {@link Some}; otherwise, throw an exception via the provided {@link Supplier}.
+ *
+ * @return value
+ */
+ @NotNull T getOrThrow(@NotNull Supplier supplier) throws X;
+
+ /**
+ * The non-empty {@link Maybe} which holds a non-null value.
+ *
+ * @param value the value
+ * @param value type
+ */
record Some(@NotNull T value) implements Maybe {
+
+
+ /**
+ * Represents a Maybe that contains a non-null value.
+ */
public Some {
requireNonNull( value );
}
- }
- record None() implements Maybe {
- // todo : ensure all None<> are equivalent...
+ @Override
+ public @NotNull Maybe biMatch(@NotNull Consumer super T> someConsumer, @NotNull Runnable noneRunner) {
+ requireNonNull( someConsumer );
+ requireNonNull( noneRunner );
+ someConsumer.accept( value );
+ return this;
+ }
- @SuppressWarnings("unchecked")
- private None coerce() {
- return (None) this;
+ @Override
+ public @NotNull Maybe filter(@NotNull Predicate super T> predicate) {
+ requireNonNull( predicate );
+ return predicate.test( value ) ? this : None.empty();
}
- }
+ @Override
+ public @NotNull U fold(@NotNull Function super T, ? extends U> fnSome, @NotNull Supplier extends U> supNone) {
+ requireNonNull( fnSome );
+ requireNonNull( supNone );
+ return requireNonNull( fnSome.apply( value ) );
+ }
- default @NotNull Maybe biMatch(@NotNull Consumer super V> okConsumer, @NotNull Runnable errRunner) {
- requireNonNull( okConsumer );
- requireNonNull( errRunner );
- switch (this) {
- case Some(var v) -> okConsumer.accept( v );
- case None __ -> errRunner.run();
+ @Override
+ public @NotNull Stream stream() {
+ return Stream.of( value );
}
- return this;
- }
+ @Override
+ public @NotNull Maybe map(@NotNull Function super T, ? extends U> fnSome) {
+ requireNonNull( fnSome );
+ return new Some<>( fnSome.apply( value ) );
+ }
- default @NotNull Maybe filter(@NotNull Predicate super V> predicate, @NotNull Supplier extends V> mapper) {
- requireNonNull( predicate );
- requireNonNull( mapper );
- return switch (this) {
- case Some(var v) when predicate.test( v ) -> this;
- default -> new Some<>( mapper.get() );
- };
- }
+ @Override
+ public Maybe match(@NotNull Consumer super T> someConsumer) {
+ requireNonNull( someConsumer );
+ someConsumer.accept( value );
+ return this;
+ }
+ @Override
+ public void consume(@NotNull Consumer super T> someConsumer) {
+ requireNonNull( someConsumer );
+ someConsumer.accept( value );
+ }
- default @NotNull T fold(@NotNull Function super V, ? extends T> fnOK,
- @NotNull Supplier extends T> fnErr) {
- requireNonNull( fnOK );
- requireNonNull( fnErr );
- return switch (this) {
- case Some(var v) -> requireNonNull( fnOK.apply( v ) );
- case None __ -> requireNonNull( fnErr.get() );
- };
- }
+ @SuppressWarnings("unchecked")
+ @Override
+ public @NotNull Maybe flatMap(@NotNull Function super T, ? extends Maybe extends U>> mapper) {
+ requireNonNull( mapper );
+ return (Maybe) requireNonNull( mapper.apply( value ) );
+ }
+ @Override
+ public boolean matches(@NotNull Predicate predicate) {
+ requireNonNull( predicate );
+ return predicate.test( value );
+ }
- default @NotNull Stream stream() {
- return switch (this) {
- case Some(var v) -> Stream.of( v );
- case None __ -> Stream.empty();
- };
- }
+ @Override
+ public boolean contains(@Nullable T v) {
+ return Objects.equals( value, v );
+ }
+ @Override
+ public boolean hasSome() {
+ return true;
+ }
- default @NotNull Maybe map(@NotNull Function super V, ? extends V2> mapper) {
- requireNonNull( mapper );
- return switch (this) {
- case Some(var v) -> new Some<>( mapper.apply( v ) ); // implicit null check
- case None v -> v.coerce();
- };
- }
+ @Override
+ public @NotNull T orElse(@NotNull T alternate) {
+ requireNonNull( value );
+ return value;
+ }
+ @Override
+ public @NotNull T orElse(@NotNull Supplier extends T> supplier) {
+ requireNonNull( supplier );
+ return value;
+ }
+ @SuppressWarnings("unchecked")
+ @Override
+ public @NotNull Maybe and(@NotNull Maybe extends U> nextMaybe) {
+ requireNonNull( nextMaybe );
+ return (Maybe) nextMaybe;
+ }
- @SuppressWarnings("unchecked")
- default @NotNull Maybe flatMap(@NotNull Function super V, ? extends Maybe extends V2>> mapper) {
- requireNonNull( mapper );
- return switch (this) {
- case Some(var v) -> (Maybe) requireNonNull( mapper.apply( v ) );
- case None v -> v.coerce();
- };
- }
+ @SuppressWarnings("unchecked")
+ @Override
+ public @NotNull Maybe and(@NotNull Supplier> nextMaybeSupplier) {
+ requireNonNull( nextMaybeSupplier );
+ return requireNonNull( (Maybe) nextMaybeSupplier.get() );
+ }
+ @Override
+ public @NotNull Maybe or(@NotNull Maybe nextMaybe) {
+ requireNonNull( nextMaybe );
+ return this;
+ }
- default boolean matches(@NotNull Predicate predicate) {
- requireNonNull( predicate );
- return switch (this) {
- case Some(var v) -> predicate.test( v );
- case None __ -> false;
- };
- }
+ @Override
+ public @NotNull Maybe or(@NotNull Supplier> nextMaybeSupplier) {
+ requireNonNull( nextMaybeSupplier );
+ return this;
+ }
+ @Override
+ public @NotNull T expect() {
+ return value;
+ }
- default boolean contains(@Nullable final V value) {
- return switch (this) {
- case Some(var v) -> Objects.equals( v, value );
- case None __ -> false;
- };
+ @Override
+ public @NotNull T getOrThrow(@NotNull Supplier supplier) throws X {
+ return value;
+ }
}
+ /**
+ * The empty {@link Maybe}.
+ *
+ * This None has a type (unliked net.xyzsd.dichotomy.None), but the type is always coerced to the needed type.
+ *
+ * @param value type
+ */
+ record None() implements Maybe {
+ private static final None