Last active
January 23, 2016 12:59
-
-
Save MrAIring/1d635425327dd6aa56fb to your computer and use it in GitHub Desktop.
Multiple results in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.Optional; | |
| import java.util.function.Consumer; | |
| import java.util.function.Function; | |
| public class Result<Ok, Err> { | |
| private Ok ok; | |
| private Err err; | |
| private boolean isOk; | |
| private Result(Ok ok, Err err, boolean isOk){ | |
| this.ok = ok; | |
| this.err = err; | |
| this.isOk = isOk; | |
| } | |
| public static <Ok, Err> Result<Ok, Err> ok(Ok ok) { | |
| return new Result<>(ok, null, true); | |
| } | |
| public static <Ok, Err> Result<Ok, Err> err(Err err) { | |
| return new Result<>(null, err, false); | |
| } | |
| public static <Ok, Err> Result<Ok, Err> fromOptional(Optional<Ok> optional, Err err) { | |
| if (optional.isPresent()) | |
| return new Result<>(optional.get(), null, true); | |
| else | |
| return new Result<>(null, err, false); | |
| } | |
| public void handle (Consumer<Ok> ifOk, Consumer<Err> ifErr) { | |
| if (isOk) | |
| ifOk.accept(ok); | |
| else | |
| ifErr.accept(err); | |
| } | |
| public <T> T project(Function<Ok, T> mapOk, Function<Err, T> mapError) { | |
| if (isOk) | |
| return mapOk.apply(ok); | |
| else | |
| return mapError.apply(err); | |
| } | |
| public <T, U> Result<T, U> mapAll(Function<Ok, T> mapOk, Function<Err, U> mapError) { | |
| if (isOk) | |
| return ok(mapOk.apply(ok)); | |
| else | |
| return err(mapError.apply(err)); | |
| } | |
| public Optional<Ok> toOptional() { | |
| if (isOk) | |
| return Optional.ofNullable(ok); | |
| else | |
| return Optional.empty(); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) return true; | |
| if (o == null || getClass() != o.getClass()) return false; | |
| Result<?, ?> result = (Result<?, ?>) o; | |
| if (isOk != result.isOk) return false; | |
| if (ok != null ? !ok.equals(result.ok) : result.ok != null) return false; | |
| return !(err != null ? !err.equals(result.err) : result.err != null); | |
| } | |
| @Override | |
| public int hashCode() { | |
| int result = ok != null ? ok.hashCode() : 0; | |
| result = 31 * result + (err != null ? err.hashCode() : 0); | |
| result = 31 * result + (isOk ? 1 : 0); | |
| return result; | |
| } | |
| @Override | |
| public String toString() { | |
| if (isOk) | |
| return "Result(Ok(" + ok + "))"; | |
| else | |
| return "Result(Err(" + err + "))"; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.Optional; | |
| import java.util.function.Consumer; | |
| import java.util.function.Function; | |
| public class ResultQuadruple<Ok, Err1, Err2, Err3> { | |
| private Ok ok; | |
| private Err1 err1; | |
| private Err2 err2; | |
| private Err3 err3; | |
| private enum Status { | |
| OK, ERR1, ERR2, ERR3 | |
| } | |
| private Status status; | |
| public ResultQuadruple(Ok ok, Err1 err1, Err2 err2, Err3 err3, Status status) { | |
| this.ok = ok; | |
| this.err1 = err1; | |
| this.err2 = err2; | |
| this.err3 = err3; | |
| this.status = status; | |
| } | |
| public static <Ok, Err1, Err2, Err3> ResultQuadruple<Ok, Err1, Err2, Err3> ok(Ok ok) { | |
| return new ResultQuadruple<>(ok, null, null, null, Status.OK); | |
| } | |
| public static <Ok, Err1, Err2, Err3> ResultQuadruple<Ok, Err1, Err2, Err3> err1(Err1 err) { | |
| return new ResultQuadruple<>(null, err, null, null, Status.ERR1); | |
| } | |
| public static <Ok, Err1, Err2, Err3> ResultQuadruple<Ok, Err1, Err2, Err3> err2(Err2 err) { | |
| return new ResultQuadruple<>(null, null, err, null, Status.ERR2); | |
| } | |
| public static <Ok, Err1, Err2, Err3> ResultQuadruple<Ok, Err1, Err2, Err3> err3(Err3 err) { | |
| return new ResultQuadruple<>(null, null, null, err, Status.ERR3); | |
| } | |
| public void handle (Consumer<Ok> ifOk, Consumer<Err1> ifErr1, Consumer<Err2> ifErr2, Consumer<Err3> ifErr3) { | |
| switch (status) { | |
| case OK : ifOk.accept(ok); break; | |
| case ERR1: ifErr1.accept(err1); break; | |
| case ERR2: ifErr2.accept(err2); break; | |
| default : ifErr3.accept(err3); | |
| } | |
| } | |
| public <T> T project(Function<Ok, T> mapOk, Function<Err1, T> mapErr1, Function<Err2, T> mapErr2, Function<Err3, T> mapErr3) { | |
| switch (status) { | |
| case OK : return mapOk.apply(ok); | |
| case ERR1: return mapErr1.apply(err1); | |
| case ERR2: return mapErr2.apply(err2); | |
| default : return mapErr3.apply(err3); | |
| } | |
| } | |
| public <T, U, W, X> ResultQuadruple<T, U, W, X> mapAll(Function<Ok, T> mapOk, Function<Err1, U> mapErr1, Function<Err2, W> mapErr2, Function<Err3, X> mapErr3) { | |
| switch (status) { | |
| case OK : return ok(mapOk.apply(ok)); | |
| case ERR1: return err1(mapErr1.apply(err1)); | |
| case ERR2: return err2(mapErr2.apply(err2)); | |
| default : return err3(mapErr3.apply(err3)); | |
| } | |
| } | |
| public boolean isOk() { | |
| return status == Status.OK; | |
| } | |
| public boolean isError() { | |
| return status != Status.OK; | |
| } | |
| public boolean isError1() { | |
| return status == Status.ERR1; | |
| } | |
| public boolean isError2() { | |
| return status == Status.ERR2; | |
| } | |
| public boolean isError3() { | |
| return status == Status.ERR3; | |
| } | |
| public Optional<Ok> toOptional() { | |
| if (isOk()) | |
| return Optional.ofNullable(ok); | |
| else | |
| return Optional.empty(); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) return true; | |
| if (o == null || getClass() != o.getClass()) return false; | |
| ResultQuadruple<?, ?, ?, ?> that = (ResultQuadruple<?, ?, ?, ?>) o; | |
| if (ok != null ? !ok.equals(that.ok) : that.ok != null) return false; | |
| if (err1 != null ? !err1.equals(that.err1) : that.err1 != null) return false; | |
| if (err2 != null ? !err2.equals(that.err2) : that.err2 != null) return false; | |
| if (err3 != null ? !err3.equals(that.err3) : that.err3 != null) return false; | |
| return status == that.status; | |
| } | |
| @Override | |
| public int hashCode() { | |
| int result = ok != null ? ok.hashCode() : 0; | |
| result = 31 * result + (err1 != null ? err1.hashCode() : 0); | |
| result = 31 * result + (err2 != null ? err2.hashCode() : 0); | |
| result = 31 * result + (err3 != null ? err3.hashCode() : 0); | |
| result = 31 * result + status.hashCode(); | |
| return result; | |
| } | |
| @Override | |
| public String toString() { | |
| switch (status) { | |
| case OK : return "Result(Ok(" + ok + "))"; | |
| case ERR1: return "Result(Err(" + err1 + "))"; | |
| case ERR2: return "Result(Err(" + err2 + "))"; | |
| default : return "Result(Err(" + err3 + "))"; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.Optional; | |
| import java.util.function.Consumer; | |
| import java.util.function.Function; | |
| public class ResultTriple<Ok, Err1, Err2> { | |
| private Ok ok; | |
| private Err1 err1; | |
| private Err2 err2; | |
| private enum Status { | |
| OK, ERR1, ERR2 | |
| } | |
| private Status status; | |
| private ResultTriple(Ok ok, Err1 err1, Err2 err2, Status status){ | |
| this.ok = ok; | |
| this.err1 = err1; | |
| this.err2 = err2; | |
| this.status = status; | |
| } | |
| public static <Ok, Err1, Err2> ResultTriple<Ok, Err1, Err2> ok(Ok ok) { | |
| return new ResultTriple<>(ok, null, null, Status.OK); | |
| } | |
| public static <Ok, Err1, Err2> ResultTriple<Ok, Err1, Err2> err1(Err1 err) { | |
| return new ResultTriple<>(null, err, null, Status.ERR1); | |
| } | |
| public static <Ok, Err1, Err2> ResultTriple<Ok, Err1, Err2> err2(Err2 err) { | |
| return new ResultTriple<>(null, null, err, Status.ERR2); | |
| } | |
| public void handle (Consumer<Ok> ifOk, Consumer<Err1> ifErr1, Consumer<Err2> ifErr2) { | |
| switch (status) { | |
| case OK : ifOk.accept(ok); break; | |
| case ERR1: ifErr1.accept(err1); break; | |
| default : ifErr2.accept(err2); | |
| } | |
| } | |
| public <T> T project(Function<Ok, T> mapOk, Function<Err1, T> mapErr1, Function<Err2, T> mapErr2) { | |
| switch (status) { | |
| case OK : return mapOk.apply(ok); | |
| case ERR1: return mapErr1.apply(err1); | |
| default : return mapErr2.apply(err2); | |
| } | |
| } | |
| public <T, U, W> ResultTriple<T, U, W> mapAll(Function<Ok, T> mapOk, Function<Err1, U> mapErr1, Function<Err2, W> mapErr2) { | |
| switch (status) { | |
| case OK : return ok(mapOk.apply(ok)); | |
| case ERR1: return err1(mapErr1.apply(err1)); | |
| default : return err2(mapErr2.apply(err2)); | |
| } | |
| } | |
| public boolean isOk() { | |
| return status == Status.OK; | |
| } | |
| public boolean isError() { | |
| return status != Status.OK; | |
| } | |
| public boolean isError1() { | |
| return status == Status.ERR1; | |
| } | |
| public boolean isError2() { | |
| return status == Status.ERR2; | |
| } | |
| public Optional<Ok> toOptional() { | |
| if (isOk()) | |
| return Optional.ofNullable(ok); | |
| else | |
| return Optional.empty(); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) return true; | |
| if (o == null || getClass() != o.getClass()) return false; | |
| ResultTriple<?, ?, ?> that = (ResultTriple<?, ?, ?>) o; | |
| if (ok != null ? !ok.equals(that.ok) : that.ok != null) return false; | |
| if (err1 != null ? !err1.equals(that.err1) : that.err1 != null) return false; | |
| if (err2 != null ? !err2.equals(that.err2) : that.err2 != null) return false; | |
| return status == that.status; | |
| } | |
| @Override | |
| public int hashCode() { | |
| int result = ok != null ? ok.hashCode() : 0; | |
| result = 31 * result + (err1 != null ? err1.hashCode() : 0); | |
| result = 31 * result + (err2 != null ? err2.hashCode() : 0); | |
| result = 31 * result + status.hashCode(); | |
| return result; | |
| } | |
| @Override | |
| public String toString() { | |
| if (isOk()) | |
| return "Result(Ok(" + ok + "))"; | |
| else if (isError1()) | |
| return "Result(Err(" + err1 + "))"; | |
| else | |
| return "Result(Err(" + err2 + "))"; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Result<InputStream, FileNotFoundException> openFileStream(String filename) { | |
| try { | |
| return Result.ok(new FileInputStream(filename)); | |
| } catch (FileNotFoundException e) { | |
| return Result.err(e); | |
| } | |
| } | |
| ... | |
| InputStream defaultStream = System.in; | |
| InputStream workWithStream = openFileStream("no such file").project( | |
| stream -> stream, | |
| notFound -> defaultStream | |
| ); | |
| openFileStream("no such file").handle( | |
| stream -> workWithStream(inputStream), | |
| err -> System.out.println("Failed to open file " + err.getMessage()) | |
| ); | |
| openFileStream().toOptional() | |
| .map(stream -> extractInfoFromStream(stream)) | |
| .ifPresent(System.out::println); | |
| ... | |
| public interface AuthenticationService { | |
| ... | |
| ResultTriple<Token, AuthenticationFailed, ServerConnectionFailed> signIn(String login, String password); | |
| } | |
| ... | |
| stubFor(postToLoginApi.willReturn(aResponse() | |
| .withFault(Fault.MALFORMED_RESPONSE_CHUNK))); | |
| assertTrue( | |
| authService.signIn("login", "password").project( | |
| token -> false, | |
| authenticationFailed -> false, | |
| serverConnectionFailed -> true) | |
| ); | |
| ... | |
| boolean isSuccessful = authService.signIn("login", "password").project( | |
| token -> { | |
| assertEquals(token.getTokenString(), "test_token"); | |
| assertTrue(authService.isSignedIn()); | |
| return true; | |
| }, | |
| authenticationFailed -> false, | |
| serverConnectionFailed -> false | |
| ); | |
| assertTrue(isSuccessful); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment