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);
        }
    }
}

你可能感兴趣的:(Java,java,exception,optional,android,函数式编程)