Java小技巧:利用Result处理空值和异常

场景

平时我们在编写Java代码中会遇到很多返回空值或抛出异常的方法,例如:

public String test() throws Exception {
    File file = new File("....");
    if (file.exists()) {
        FileInputStream stream = new FileInputStream(file);
        //...
        return "";
    } else {
        return null;
    }
}

而调用这个方法的代码可能就是:

try {
    String str = test();
    if (str != null) {
        //do something...
    } else {
        //do something...
    }
} catch (Exception e) {
    e.printStackTrace();//or ignore
}

这里我们调用test时并不知道返回的是否为空,需要对返回值做一些防护,如果test使用的是运行时异常,那么连是否会抛出异常也不清楚了。

在这种情况下,我们需要表示 test 的返回值为 String|null|Exception 类型,遗憾的是Java并不提供联合类型的语法。我们可以利用 Java 8 的 Optional 类来表示“有或者没有“这样的概念,但是它并没有异常的意思。在这样的场景下,可以参考 Optional 的方式,通过定义 Result 类来实现这样的效果。

Result API 介绍

1. Result 的创建

Result.empty();             //直接获取空的Result
Result.success(value);      //直接获取带值的Result
Result.failure(exception);  //使用异常或异常信息来获取错误的Result
Result.of(...);             //根据值返回对应的成功、空或失败的Result
Result.from(...);           //从一些过程来获取值

2. Result 的类型断言

result.isEmpty();
result.isPresent();
result.isError();

3. Result 内容获取

result.get();                   //直接获取值,可能为null
result.getOr(() -> "empty");    //获取值,或者用制定过程的返回值
result.getOrElse("empty");      //获取值,或者默认值
result.getOrThrow();            //获取值,或者抛出异常

4. Result 的流式API

这些API包括 filter、map、flatMap、forEach、forEachOrThrow、forEachOrException,具体定义见最后的代码,下面是使用示例:

result.filter(s -> s.length() > 0)  //过滤空字符串
        .map(s -> "str:" + s)       //添加前缀
        .forEachOrException((String s) -> {
            //处理结果
        })
        .forEach((Exception e) -> {
            //处理异常
        })

result.filter(s -> s.length() > 0)  //过滤空字符串
        .map(s -> "str:" + s)       //添加前缀
        .forEachOrThrow(s -> {
            //处理结果,如果不是Success的Result就抛出异常
        });

Result类的定义

本类的定义来自于《Java 函数式编程》,并对工作做一些调整,扩展了几个简单的API。定义如下:

public abstract class Result<V> implements Serializable {

    private final static Empty empty = new Empty();

    private Result() {
    }

    public abstract boolean isEmpty();

    public abstract boolean isError();

    public abstract boolean isPresent();

    public abstract V get();

    public abstract V getOrElse(final V defaultValue);

    public abstract V getOr(final Supplier<V> vSupplier);

    public abstract V getOrThrow() throws Exception;

    public abstract <U> Result<U> map(Function<V, U> f);

    public abstract <U> Result<U> flatMap(Function<V, Result<U>> f);

    public abstract void forEach(Consumer<V> consumer);

    public abstract void forEachOrThrow(Consumer<V> consumer);

    public abstract Result<Exception> forEachOrException(Consumer<V> consumer);

    public Result<V> orElse(Supplier<Result<V>> defaultValueSupplier) {
        return map(v -> this).getOr(defaultValueSupplier);
    }

    public Result<V> filter(Function<V, Boolean> p) {
        return flatMap(v -> p.apply(v)
                ? success(v)
                : failure("Condition not matched"));
    }

    public Result<V> filter(Function<V, Boolean> p, String message) {
        return flatMap(v -> p.apply(v)
                ? success(v)
                : failure(message));
    }

    public boolean exists(Function<V, Boolean> p) {
        return map(p).getOrElse(false);
    }

    private static class Empty<V> extends Result<V> {

        Empty() {
            super();
        }

        @Override
        public boolean isEmpty() {
            return true;
        }

        @Override
        public boolean isError() {
            return false;
        }

        @Override
        public boolean isPresent() {
            return false;
        }

        @Override
        public V get() {
            return null;
        }

        @Override
        public V getOrElse(V defaultValue) {
            return defaultValue;
        }

        @Override
        public V getOr(Supplier<V> vSupplier) {
            return vSupplier.get();
        }

        @Override
        public V getOrThrow() throws Exception {
            throw new IllegalStateException("empty value!");
        }

        @Override
        public <U> Result<U> map(Function<V, U> f) {
            return empty();
        }

        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            return empty();
        }

        @Override
        public void forEach(Consumer<V> consumer) {

        }

        @Override
        public void forEachOrThrow(Consumer<V> consumer) {

        }

        @Override
        public Result<Exception> forEachOrException(Consumer<V> consumer) {
            return empty();
        }
    }

    private static class Failure<V> extends Empty<V> {
        private final RuntimeException exception;

        Failure(RuntimeException exception) {
            super();
            this.exception = exception;
        }

        Failure(String message) {
            super();
            this.exception = new IllegalStateException(message);
        }

        Failure(Exception e) {
            super();
            this.exception = new IllegalStateException(e.getMessage(), e);
        }

        @Override
        public V getOrElse(V defaultValue) {
            return defaultValue;
        }

        @Override
        public V getOr(Supplier<V> vSupplier) {
            return vSupplier.get();
        }

        @Override
        public <U> Result<U> map(Function<V, U> f) {
            return failure(exception);
        }

        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            return failure(exception);
        }

        @Override
        public void forEachOrThrow(Consumer<V> consumer) {
            throw exception;
        }

        @Override
        public Result<Exception> forEachOrException(Consumer<V> consumer) {
            return success(exception);
        }

        @Override
        public V getOrThrow() throws Exception {
            throw exception;
        }

        @Override
        public boolean isError() {
            return true;
        }
    }

    private static class Success<V> extends Result<V> {
        private final V value;

        Success(V value) {
            this.value = value;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public boolean isError() {
            return false;
        }

        @Override
        public boolean isPresent() {
            return true;
        }

        @Override
        public V get() {
            return value;
        }

        @Override
        public V getOrElse(V defaultValue) {
            return value;
        }

        @Override
        public V getOr(Supplier<V> vSupplier) {
            return value;
        }

        @Override
        public V getOrThrow() {
            return value;
        }

        @Override
        public <U> Result<U> map(Function<V, U> f) {
            try {
                return success(f.apply(value));
            } catch (Exception e) {
                return failure(e);
            }
        }

        @Override
        public <U> Result<U> flatMap(Function<V, Result<U>> f) {
            try {
                return f.apply(value);
            } catch (Exception e) {
                return failure(e);
            }
        }

        @Override
        public void forEach(Consumer<V> consumer) {
            consumer.accept(value);
        }

        @Override
        public void forEachOrThrow(Consumer<V> consumer) {
            consumer.accept(value);
        }

        @Override
        public Result<Exception> forEachOrException(Consumer<V> consumer) {
            consumer.accept(value);
            return empty();
        }
    }

    public static <V> Result<V> failure(String message) {
        return new Failure<>(message);
    }

    public static <V> Result<V> failure(RuntimeException e) {
        return new Failure<>(e);
    }

    public static <V> Result<V> failure(Exception e) {
        return new Failure<>(e);
    }

    public static <V> Result<V> success(V value) {
        return new Success<>(value);
    }

    public static <V> Result<V> empty() {
        return empty;
    }

    public static <V> Result<V> of(V value) {
        return value != null
                ? success(value)
                : empty();
    }

    public static <V> Result<V> of(V value, String message) {
        return value != null
                ? success(value)
                : failure(message);
    }

    public static <V> Result<V> of(Function<V, Boolean> p, V value) {
        try {
            return p.apply(value)
                    ? success(value)
                    : empty();
        } catch (Exception e) {
            String errMessage = String.format("Exception while evaluating predicate: %s", e.getMessage());
            return failure(new IllegalStateException(errMessage, e));
        }
    }

    public static <V> Result<V> of(Function<V, Boolean> p, V value, String message) {
        try {
            return p.apply(value)
                    ? success(value)
                    : failure(String.format(message, value));
        } catch (Exception e) {
            String errMessage = String.format("Exception while evaluating predicate: %s", String.format(message, value));
            return failure(errMessage);
        }
    }

    public static <V> Result<V> from(Supplier<V> valueSupplier) {
        final V value;
        try {
            value = valueSupplier.get();
        } catch (Exception e) {
            String errMessage = String.format("Exception while evaluating value supplier: %s", e.getMessage());
            return failure(new IllegalStateException(errMessage, e));
        }
        return of(value);
    }

    public static <V> Result<V> from(Supplier<V> valueSupplier, String message) {
        final V value;
        try {
            value = valueSupplier.get();
        } catch (Exception e) {
            String errMessage = String.format("Exception while evaluating value supplier: %s", e.getMessage());
            return failure(new IllegalStateException(errMessage, e));
        }
        return of(value, message);
    }

    public static <V> Result<V> from(Function<V, Boolean> p, Supplier<V> valueSupplier) {
        final V value;
        try {
            value = valueSupplier.get();
        } catch (Exception e) {
            String errMessage = String.format("Exception while evaluating value supplier: %s", e.getMessage());
            return failure(new IllegalStateException(errMessage, e));
        }
        return of(p, value);
    }

    public static <V> Result<V> from(Function<V, Boolean> p, Supplier<V> valueSupplier, String message) {
        final V value;
        try {
            value = valueSupplier.get();
        } catch (Exception e) {
            return failure(String.format("Exception while evaluating value supplier: %s", message));
        }
        return of(p, value, message);
    }

    public static <A, B> Function<Result<A>, Result<B>> lift(Function<A, B> function) {
        return aResult -> {
            try {
                return aResult.map(function);
            } catch (Exception e) {
                return failure(e);
            }
        };
    }
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值