游戏系统会有大量的配置信息,包括从数据库中读取的配置,还有从各种文件中读取的配置,都伴随着抛出NullPointerException的可能,如果能够减少空指针,系统会更加稳定。
Java8的Optional能够很好地表示可选数据,但是对于错误导致的数据缺失,无法提供有用的信息,如果仅仅使用Exception来表示错误,又会失去了使用Optional的所有好处。
一个可行的方案,就是定义三种对象来描述数据缺失:Success、Failure、Empty。
/**
* 当结果源自错误时候,Java8的Optional<>无法得到引起缺失的原因,这个类能区分不同情况引起的数据缺失问题,包含了错误的具体信息。
*
* 1.计算错误、异常或者逻辑错误引起的数据缺失,Failure
*
* 2.非错误引起的数据缺失(可选数据),Empty
*
* 3.成功时,包装结果值,Success
*
* @author 林子豪
*
* @param <V> 结果值的数据类型
*/
public abstract class ResultOption<V> {
@SuppressWarnings("rawtypes")
private static ResultOption empty = new Empty();
private ResultOption() {}
// 空对象
private static class Empty<V> extends ResultOption<V> {
private Empty() {}
@Override
public V getOrElse(V defaultValue) {
return defaultValue;
}
@Override
public V getOrElse(Supplier<V> defaultValue) {
return defaultValue.get();
}
@Override
public <U> ResultOption<U> map(Function<V, U> f) {
return empty();
}
@Override
public <U> ResultOption<U> flatMap(Function<V, ResultOption<U>> f) {
return empty();
}
@Override
public String toString() {
return "Empty()";
}
@Override
public ResultOption<V> mapFailure(String detail) {
return this;
}
@Override
public void ifSuccess(Consumer<V> effect) {
// 什么也不做
}
@Override
public void ifSuccessOrThrow(Consumer<V> effect) {
// 数据的缺失不应该作为错误 ,什么也不做
}
@Override
public ResultOption<RuntimeException> ifSuccessOrException(Consumer<V> effect) {
return empty();
}
@Override
public ResultOption<String> ifSuccessOrDetail(Consumer<V> effect) {
return empty();
}
@Override
public V getOrElseThrow() {
throw new IllegalStateException("get() called on empty.");
}
@Override
public V getOrElseThrow(String message) {
throw new IllegalStateException(message);
}
@Override
public ResultOption<ResultCode> ifSuccessOrResultCode(Consumer<V> effect) {
return empty();
}
@Override
public ResultCode getCode() {
return ResultCode.DATA_EMPTY;
}
@Override
public String getDetail() {
return "";
}
@Override
public ResultCode andThen(Function<V, ResultCode> f) {
return ResultCode.DATA_EMPTY;
}
}
// fail对象
private static class Failure<V> extends ResultOption<V> {
private final ResultCode resultCode;
//如果要返回额外的信息,可以往detail里面塞数据
private final String detail;
private Failure(ResultCode resultCode) {
this.resultCode = resultCode;
this.detail = resultCode.name();
}
private Failure(int code) {
this.resultCode = ResultCode.getCode(code);
this.detail = resultCode.name();
}
private Failure(ResultCode resultCode, String detail) {
this.resultCode = resultCode;
this.detail = WebUtil.getString(detail, resultCode.name());
}
private Failure(int code, String detail) {
this.resultCode = ResultCode.getCode(code);
this.detail = WebUtil.getString(detail, resultCode.name());
}
private Failure(Exception exception) {
this.resultCode = ResultCode.EXCEPTION;
this.detail = WebUtil.getString(exception.getMessage(), resultCode.name());
}
private Failure(Exception exception, String detail) {
this.resultCode = ResultCode.EXCEPTION;
this.detail = WebUtil.getString(detail, resultCode.name());
}
@Override
public String toString() {
return String.format("Failure(%s)", detail);
}
@Override
public V getOrElse(V defaultValue) {
return defaultValue;
}
@Override
public V getOrElse(Supplier<V> defaultValue) {
return defaultValue.get();
}
@Override
public <U> ResultOption<U> map(Function<V, U> f) {
return failure(resultCode, detail);
}
@Override
public <U> ResultOption<U> flatMap(Function<V, ResultOption<U>> f) {
return failure(resultCode, detail);
}
@Override
public ResultOption<V> mapFailure(String detail) {
return failure(resultCode, detail);
}
@Override
public void ifSuccess(Consumer<V> effect) {
// 什么也不做
}
@Override
public void ifSuccessOrThrow(Consumer<V> effect) {
throw new IllegalStateException(detail);
}
@Override
public ResultOption<RuntimeException> ifSuccessOrException(Consumer<V> effect) {
// 保持原来的异常信息,以便做其他处理
return success(new IllegalStateException(detail));
}
@Override
public ResultOption<String> ifSuccessOrDetail(Consumer<V> effect) {
return success(detail);
}
@Override
public V getOrElseThrow() {
throw new IllegalStateException(detail);
}
@Override
public V getOrElseThrow(String message) {
throw new IllegalStateException(message);
}
@Override
public ResultOption<ResultCode> ifSuccessOrResultCode(Consumer<V> effect) {
return success(resultCode);
}
@Override
public ResultCode getCode() {
return resultCode;
}
@Override
public String getDetail() {
return detail;
}
@Override
public ResultCode andThen(Function<V, ResultCode> f) {
return resultCode;
}
}
// success对象
private static class Success<V> extends ResultOption<V> {
private final V value;
private Success(V value) {
this.value = value;
}
@Override
public String toString() {
return String.format("Success(%s)", value.toString());
}
@Override
public V getOrElse(V defaultValue) {
return value;
}
@Override
public V getOrElse(Supplier<V> defaultValue) {
return value;
}
@Override
public <U> ResultOption<U> map(Function<V, U> f) {
try {
return success(f.apply(value));
} catch (Exception e) {
return failure(e);
}
}
@Override
public <U> ResultOption<U> flatMap(Function<V, ResultOption<U>> f) {
try {
return f.apply(value);
} catch (Exception e) {
return failure(e);
}
}
@Override
public ResultOption<V> mapFailure(String detail) {
return this;
}
@Override
public void ifSuccess(Consumer<V> effect) {
effect.accept(value);
}
@Override
public void ifSuccessOrThrow(Consumer<V> effect) {
ifSuccess(effect);
}
@Override
public ResultOption<RuntimeException> ifSuccessOrException(Consumer<V> effect) {
effect.accept(value);
// 因为没有RuntimeException,所以返回empty()
return empty();
}
@Override
public ResultOption<String> ifSuccessOrDetail(Consumer<V> effect) {
effect.accept(value);
return empty();
}
@Override
public V getOrElseThrow() {
return this.value;
}
@Override
public V getOrElseThrow(String message) {
return this.value;
}
@Override
public ResultOption<ResultCode> ifSuccessOrResultCode(Consumer<V> effect) {
effect.accept(value);
return empty();
}
@Override
public ResultCode getCode() {
return ResultCode.SUCCESS;
}
@Override
public String getDetail() {
return "";
}
@Override
public ResultCode andThen(Function<V, ResultCode> f) {
return f.apply(value);
}
}
/ 静态方法
@SuppressWarnings("unchecked")
public static <V> ResultOption<V> empty() {
return empty;
}
public static <T, V> ResultOption<T> failure(ResultOption<V> failure) {
return new Failure<>(failure.getCode(), failure.getDetail());
}
public static <V> ResultOption<V> failure(int code) {
return new Failure<>(code);
}
public static <V> ResultOption<V> failure(ResultCode resultCode) {
return new Failure<>(resultCode);
}
public static <V> ResultOption<V> failure(int code, String detail) {
return new Failure<>(code, detail);
}
public static <V> ResultOption<V> failure(ResultCode resultCode, String detail) {
return new Failure<>(resultCode, detail);
}
public static <V> ResultOption<V> failure(Exception exception) {
return new Failure<>(exception);
}
public static <V> ResultOption<V> failure(Exception exception, String detail) {
return new Failure<>(exception, detail);
}
public static <V> ResultOption<V> success(V value) {
return new Success<>(value);
}
public static <V> ResultOption<V> of(V value) {
return value != null ? success(value) : empty();
}
public static <V> ResultOption<V> of(V value, ResultCode code) {
return value != null ? success(value) : failure(code);
}
public static <V> ResultOption<V> of(V value, String reason) {
return value != null ? success(value) : failure(ResultCode.DATA_EMPTY, reason);
}
public static <V> ResultOption<V> of(V value, ResultCode code, String reason) {
return value != null ? success(value) : failure(code, reason);
}
public static <V> ResultOption<V> of(Optional<V> jdkOptional) {
return jdkOptional.isPresent() ? success(jdkOptional.get()) : empty();
}
public static <V> ResultOption<V> of(Optional<V> jdkOptional, ResultCode resultCode) {
return jdkOptional.isPresent() ? success(jdkOptional.get()) : failure(resultCode);
}
public static <V> ResultOption<V> of(Optional<V> jdkOptional, ResultCode resultCode, String detail) {
return jdkOptional.isPresent() ? success(jdkOptional.get()) : failure(resultCode, detail);
}
///实例方法
public ResultOption<V> filter(Function<V, Boolean> p) {
return flatMap(x -> p.apply(x) ? this : failure(ResultCode.CONDITION_NOT_MATCH, "Condition not matched"));
}
public ResultOption<V> filter(Function<V, Boolean> p, String message) {
return flatMap(x -> p.apply(x) ? this : failure(ResultCode.CONDITION_NOT_MATCH, message));
}
public boolean exists(Function<V, Boolean> p) {
return map(p).getOrElse(false);
}
public ResultOption<V> orElse(Supplier<ResultOption<V>> defaultValue) {
return map(x -> this).getOrElse(defaultValue);
}
public boolean isSuccess() {
return this instanceof Success;
}
public boolean isNotSuccess() {
return !(this instanceof Success);
}
public boolean isEmpty() {
return (this instanceof Empty);
}
public boolean isFailure() {
return (this instanceof Failure);
}
// 抽象方法
public abstract V getOrElseThrow();
public abstract V getOrElseThrow(String message);
public abstract V getOrElse(final V defaultValue);
public abstract V getOrElse(final Supplier<V> defaultValue);
public abstract <U> ResultOption<U> map(Function<V, U> f);
public abstract <U> ResultOption<U> flatMap(Function<V, ResultOption<U>> f);
//转化成Failure对象
public abstract ResultOption<V> mapFailure(String detail);
// consumer就是作用,可以修改外界的任何东西
public abstract void ifSuccess(Consumer<V> effect);
public abstract void ifSuccessOrThrow(Consumer<V> effect);
//数据缺失的时候返回具体错误信息
public abstract ResultOption<String> ifSuccessOrDetail(Consumer<V> effect);
//数据缺失的时候返回具体的异常对象,而不是直接抛出异常
public abstract ResultOption<RuntimeException> ifSuccessOrException(Consumer<V> effect);
//数据缺失的时候返回具体的错误码
public abstract ResultOption<ResultCode> ifSuccessOrResultCode(Consumer<V> effect);
public abstract ResultCode andThen(Function<V, ResultCode> f);
public abstract ResultCode getCode();
public abstract String getDetail();
}