Commit fac86561 authored by pysaumont's avatar pysaumont
Browse files

Fixes after AC review for chapter 13

parent 49a8af14
package com.fpinjava.io.exercise13_02;
package com.fpinjava.io.exercise13_02_;
import com.fpinjava.common.Effect;
import com.fpinjava.common.Function;
......
package com.fpinjava.io.exercise13_01;
import com.fpinjava.common.Effect;
import com.fpinjava.common.Function;
import com.fpinjava.common.Supplier;
import java.io.Serializable;
import java.util.Objects;
public abstract class Result<T> implements Serializable {
@SuppressWarnings("rawtypes")
private static Result empty = new Empty();
private Result() {
}
public abstract T getOrElse(final Supplier<T> defaultValue);
public abstract <U> U foldLeft(U identity, Function<U, Function<T, U>> f);
public abstract <U> U foldRight(U identity, Function<T, Function<U, U>> f);
public abstract <U> Result<U> map(Function<T, U> f);
public abstract <U> Result<U> flatMap(Function<T, Result<U>> f);
public abstract Result<T> mapFailure(String s);
public abstract Result<T> mapFailure(String s, Exception e);
public abstract Result<T> mapFailure(Exception e);
public abstract Result<T> failIfEmpty(String message);
public abstract void forEach(Effect<T> ef);
public T getOrElse(final T defaultValue) {
return getOrElseViaFoldLeft(defaultValue);
}
public T getOrElseViaFoldLeft(final T defaultValue) {
return foldLeft(defaultValue, d -> v -> v);
}
public T getOrElseViaFoldRight(final T defaultValue) {
return foldRight(defaultValue, v -> d -> v);
}
public Result<T> orElse(Supplier<Result<T>> defaultValue) {
return map(x -> this).getOrElse(defaultValue);
}
public Result<T> filter(Function<T, Boolean> p) {
return flatMap(x -> p.apply(x)
? this
: failure("Condition not matched"));
}
public Result<T> filter(Function<T, Boolean> p, String message) {
return flatMap(x -> p.apply(x)
? this
: failure(message));
}
public boolean exists(Function<T, Boolean> p) {
return map(p).getOrElse(false);
}
private static class Empty<T> extends Result<T> {
public Empty() {
super();
}
@Override
public <U> Result<U> map(Function<T, U> f) {
return empty();
}
@Override
public <U> Result<U> flatMap(Function<T, Result<U>> f) {
return empty();
}
@Override
public Result<T> mapFailure(String s) {
return this;
}
@Override
public Result<T> mapFailure(String s, Exception e) {
return this;
}
@Override
public Result<T> mapFailure(Exception e) {
return this;
}
@Override
public Result<T> failIfEmpty(String message) {
return failure(message);
}
@Override
public void forEach(Effect<T> ef) {
throw new IllegalStateException("To be implemented");
}
@Override
public String toString() {
return "Empty()";
}
@Override
public T getOrElse(Supplier<T> defaultValue) {
return defaultValue.get();
}
/**
* There is only one instance of Empty, so all Empty are equals.
*/
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int hashCode() {
return 0;
}
@Override
public <U> U foldLeft(U identity, Function<U, Function<T, U>> f) {
return identity;
}
@Override
public <U> U foldRight(U identity, Function<T, Function<U, U>> f) {
return identity;
}
}
private static class Failure<T> extends Empty<T> {
private final RuntimeException exception;
private Failure(String message) {
super();
this.exception = new IllegalStateException(message);
}
private Failure(RuntimeException e) {
super();
this.exception = e;
}
private Failure(Exception e) {
super();
this.exception = new IllegalStateException(e.getMessage(), e);
}
@Override
public String toString() {
return String.format("Failure(%s)", exception.getMessage());
}
@Override
public <U> Result<U> map(Function<T, U> f) {
return failure(exception);
}
@Override
public <U> Result<U> flatMap(Function<T, Result<U>> f) {
return failure(exception);
}
@Override
public Result<T> mapFailure(String s) {
return failure(new IllegalStateException(s, exception));
}
@Override
public Result<T> mapFailure(String s, Exception e) {
return failure(new IllegalStateException(s, e));
}
@Override
public Result<T> mapFailure(Exception e) {
return failure(e);
}
@Override
public Result<T> failIfEmpty(String message) {
return failure(message);
}
/**
* Failures are equals only if they are the same object.
*/
@Override
public boolean equals(Object o) {
return this == o;
}
/**
* We need a better hashCode method returning a different hashCode for
* all failures. See http://code.google.com/p/smhasher and:or the Guava
* Hashing class for examples.
*/
@Override
public int hashCode() {
return this.exception.hashCode();
}
}
private static class Success<T> extends Result<T> {
private final T value;
private Success(T value) {
super();
this.value = value;
}
@Override
public String toString() {
return String.format("Success(%s)", value.toString());
}
@Override
public T getOrElse(Supplier<T> defaultValue) {
return value;
}
@Override
public <U> Result<U> map(Function<T, U> f) {
return success(f.apply(value));
}
@Override
public <U> Result<U> flatMap(Function<T, Result<U>> f) {
return f.apply(value);
}
@Override
public Result<T> mapFailure(String s) {
return this;
}
@Override
public Result<T> mapFailure(String s, Exception e) {
return this;
}
@Override
public Result<T> mapFailure(Exception e) {
return this;
}
@Override
public Result<T> failIfEmpty(String message) {
return this;
}
@Override
public void forEach(Effect<T> ef) {
throw new IllegalStateException("To be implemented");
}
@Override
public boolean equals(Object o) {
return (this == o || o instanceof Success)
&& this.value.equals(((Success<?>) o).value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public <U> U foldLeft(U identity, Function<U, Function<T, U>> f) {
return f.apply(identity).apply(this.value);
}
@Override
public <U> U foldRight(U identity, Function<T, Function<U, U>> f) {
return f.apply(this.value).apply(identity);
}
}
public static <T> Result<T> failure(String message) {
return new Failure<>(message);
}
public static <T> Result<T> failure(Exception e) {
return new Failure<>(e);
}
public static <T> Result<T> failure(RuntimeException e) {
return new Failure<>(e);
}
public static <T> Result<T> success(T value) {
return new Success<>(value);
}
@SuppressWarnings("unchecked")
public static <T> Result<T> empty() {
return empty;
}
public static <T> Result<T> of(T value) {
return value != null
? success(value)
: empty();
}
public static <T> Result<T> of(T value, String message) {
return value != null
? success(value)
: failure(message);
}
public static <T> Result<T> of(Function<T, Boolean> predicate, T value) {
try {
return predicate.apply(value)
? success(value)
: empty();
} catch (Exception e) {
String errMessage =
String.format("Exception while evaluating predicate: %s", value);
return Result.failure(new IllegalStateException(errMessage, e));
}
}
public static <T> Result<T> of(Function<T, Boolean> predicate,
T value, String message) {
try {
return predicate.apply(value)
? Result.success(value)
: Result.failure(String.format(message, value));
} catch (Exception e) {
String errMessage =
String.format("Exception while evaluating predicate: %s",
String.format(message, value));
return Result.failure(new IllegalStateException(errMessage, e));
}
}
public static <A, B> Function<Result<A>, Result<B>> lift(final Function<A, B> f) {
return x -> x.map(f);
}
public static <A, B, C> Function<Result<A>, Function<Result<B>, Result<C>>> lift2(Function<A, Function<B, C>> f) {
return a -> b -> a.map(f).flatMap(b::map);
}
public static <A, B, C, D> Function<Result<A>, Function<Result<B>, Function<Result<C>, Result<D>>>> lift3(Function<A, Function<B, Function<C, D>>> f) {
return a -> b -> c -> a.map(f).flatMap(b::map).flatMap(c::map);
}
public static <A, B, C> Result<C> map2(Result<A> a, Result<B> b, Function<A, Function<B, C>> f) {
return lift2(f).apply(a).apply(b);
}
}
package com.fpinjava.io.exercise13_04;
package com.fpinjava.io.exercise13_02;
import com.fpinjava.common.Effect;
......@@ -115,7 +115,7 @@ public abstract class Result<T> implements Serializable {
@Override
public Result<RuntimeException> forEachOrException(Effect<T> c) {
throw new IllegalStateException("To be implemented");
return empty();
}
@Override
......@@ -213,7 +213,7 @@ public abstract class Result<T> implements Serializable {
@Override
public Result<RuntimeException> forEachOrException(Effect<T> c) {
throw new IllegalStateException("To be implemented");
return success(exception);
}
@Override
......@@ -305,7 +305,8 @@ public abstract class Result<T> implements Serializable {
@Override
public Result<RuntimeException> forEachOrException(Effect<T> e) {
throw new IllegalStateException("To be implemented");
e.apply(this.value);
return empty();
}
@Override
......
package com.fpinjava.io.exercise13_03;
package com.fpinjava.io.exercise13_02;
import com.fpinjava.common.Function;
......@@ -8,7 +8,6 @@ public class ResultTest {
public static void main(String... args) {
Result<Integer> ra = Result.success(4);
Result<Integer> rb = Result.success(0);
Function<Integer, Result<Double>> inverse = x -> x != 0
......@@ -19,9 +18,13 @@ public class ResultTest {
Result<Double> rt2 = rb.flatMap(inverse);
System.out.print("Inverse of 4: ");
rt1.forEach(System.out::println);
rt1.forEachOrFail(System.out::println).forEach(ResultTest::log);
System.out.print("Inverse of 0: ");
rt2.forEach(System.out::println);
rt2.forEachOrFail(System.out::println).forEach(ResultTest::log);
}
private static void log(String s) {
System.out.println(s);
}
}
package com.fpinjava.io.exercise13_05;
import com.fpinjava.common.Result;
import com.fpinjava.common.Stream;
import com.fpinjava.common.Tuple;
package com.fpinjava.io.exercise13_03;
public class ReadConsole {
......
package com.fpinjava.io.exercise13_03;
import com.fpinjava.common.Effect;
import com.fpinjava.common.Function;
import com.fpinjava.common.Supplier;
import java.io.Serializable;
import java.util.Objects;
public abstract class Result<T> implements Serializable {
@SuppressWarnings("rawtypes")
private static Result empty = new Empty();
private Result() {
}
public abstract T getOrElse(final Supplier<T> defaultValue);
public abstract <U> U foldLeft(U identity, Function<U, Function<T, U>> f);
public abstract <U> U foldRight(U identity, Function<T, Function<U, U>> f);
public abstract <U> Result<U> map(Function<T, U> f);
public abstract <U> Result<U> flatMap(Function<T, Result<U>> f);
public abstract Result<T> mapFailure(String s);
public abstract Result<T> mapFailure(String s, Exception e);
public abstract Result<T> mapFailure(Exception e);
public abstract Result<T> failIfEmpty(String message);
public abstract void forEach(Effect<T> ef);
public abstract void forEachOrThrow(Effect<T> c);
public T getOrElse(final T defaultValue) {
return getOrElseViaFoldLeft(defaultValue);
}
public T getOrElseViaFoldLeft(final T defaultValue) {
return foldLeft(defaultValue, d -> v -> v);
}
public T getOrElseViaFoldRight(final T defaultValue) {
return foldRight(defaultValue, v -> d -> v);
}
public Result<T> orElse(Supplier<Result<T>> defaultValue) {
return map(x -> this).getOrElse(defaultValue);
}
public Result<T> filter(Function<T, Boolean> p) {
return flatMap(x -> p.apply(x)
? this
: failure("Condition not matched"));
}
public Result<T> filter(Function<T, Boolean> p, String message) {
return flatMap(x -> p.apply(x)
? this
: failure(message));
}
public boolean exists(Function<T, Boolean> p) {
return map(p).getOrElse(false);
}
private static class Empty<T> extends Result<T> {
public Empty() {
super();
}
@Override
public <U> Result<U> map(Function<T, U> f) {
return empty();
}
@Override
public <U> Result<U> flatMap(Function<T, Result<U>> f) {
return empty();
}