java-8 – Optional.ifAbsentThrow()?

前端之家收集整理的这篇文章主要介绍了java-8 – Optional.ifAbsentThrow()?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
假设我需要找到某个订单的值,然后获取其id,然后获取其localized-id.如果我不能这样做,我想抛出异常:
return values.stream()
             .filter(value -> value.getOrder("order") == order)
             .findAny()
             .map(Attribute::getId)
             .map(Id::getLocalizedId)
             .orElseThrow(() -> new RuntimeException("Could not get the localized id of the value of order " + order));

问题是异常不是很详细:它告诉我我不能获得本地化的id,但不是为什么.

我想念一些Optional.ifAbsentThrow方法,它允许我这样做:

return values.stream()
             .filter(value -> value.getOrder("order") == order)
             .findAny()
             .ifAbsentThrow(() -> new RuntimeException("Could not find value of order " + order));
             .map(Attribute::getId)
             .ifAbsentThrow(() -> new RuntimeException("Value of order " + order + " has no id"));
             .map(Id::getLocalizedId)
             .orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));

为了解决这个问题,我创建了以下ifAbsentThrow方法

public static <T,X extends RuntimeException> Predicate<T> ifAbsentThrow(Supplier<? extends X> exceptionSupplier) throws RuntimeException {
    return valor -> { 
                    if (valor == null) throw exceptionSupplier.get();
                    return true; 
                    };
    }

我这样使用它:

return values.stream()
             .filter(value -> value.getOrder("order") == order)
             .findAny()
             .filter(ifAbsentThrow(() -> new RuntimeException("Could not find value of order " + order));
             .map(Attribute::getId)
             .filter(ifAbsentThrow(() -> new RuntimeException("Value of order " + order + " has no id"));
             .map(Id::getLocalizedId)
             .orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));

我的问题:

> 1)我在这里遗漏了什么吗?可选是真的错过了这个
功能或我不应该出于某种原因这样做?
> 2)是否有更好的,推荐的方式抛出更详细的例外
对于缺失值?

编辑:现在在我看来,Optional.ifAbsentThrow不存在,因为它将是一种处理空值的方法,而Optional是首先不使用空值.可选显然不能很好地使用空值,如果你混合它会变得冗长.然而,在现实世界中,我发现很难处理这个全有或全无的命题:一些代码被转换为Optionals,而其他代码仍然使用可空值.为了帮助我混合它们,并且只在必要时将nullables重构为Optionals,我相信我将使用下面的GetNonNull类,它基于我从@Alex和@Holgers在本页中获得的知识.

解决方法

可选是为了封装可能缺少的值.如果你执行像ifAbsentThrow这样的操作,那么将值作为Optional是没有意义的,因为你已经知道它在正常完成时并不存在.所以orElseThrow做你想要的但返回一个普通的对象,因为它不再是可选的.

当然,您可以将函数应用于普通对象并将其结果再次包装为Optional,如Alex suggested,但问问自己这是否真的比直接代码有所改进:

Attribute a=values.stream().filter(value -> value.getOrder("order") == order).findAny()
    .orElseThrow(() -> new RuntimeException("Could not find value of order " + order));
Id id=a.getId();
if(id==null)
    throw new RuntimeException("Value of order " + order + " has no id");
String name=id.getName();
if(name==null)
    throw new RuntimeException(
        "Could get the id but not the localized id of the value of order " + order);
return name;

您还可以创建一个实用程序方法,提供应用函数的操作,并在函数返回null时正确抛出:

static <T,R,E extends Throwable> R get(T o,Function<T,R> f,Supplier<E> s) throws E {
    return Optional.ofNullable(f.apply(o)).orElseThrow(s);
}

使用此方法,您的操作变为:

return get(ContainingClass.<Attribute,Id,RuntimeException>get(
 values.stream().filter(value -> value.getOrder("order") == order).findAny()
   .orElseThrow(  () -> new RuntimeException("Could not find value of order " + order)),Attribute::getId,() -> new RuntimeException("Value of order " + order + " has no id")),Id::getName,() -> new RuntimeException(
     "Could get the id but not the localized id of the value of order " + order));

(不幸的是,编译器的类型推断达到了极限)

最后一种方法是创建Optional的替代方案,它不仅带有可能缺席的值,还有可选的错误

public final class Failable<T,E extends Throwable> {
    private final T value;
    private final E failure;
    private Failable(T value,E failure) {
        this.value=value;
        this.failure=failure;
        if(value==null && failure==null) throw new NullPointerException();
    }
    public T get() throws E {
        if(failure!=null) throw failure;
        return value;
    }
    public <R> Failable<R,E> map(Function<T,Supplier<E> s) {
        if(value!=null) {
            R result=f.apply(value);
            return new Failable<>(result,result!=null? null: s.get());
        }
        // already Failed,types of R and T are irrelevant
        @SuppressWarnings("unchecked") Failable<R,E> f0=(Failable)this;
        return f0;
    }
    public static <T,E extends Throwable> Failable<T,E> of(Optional<T> o,Supplier<E> s) {
        return o.map(t -> new Failable<>(t,(E)null))
                .orElseGet(()->new Failable<>(null,s.get()));
    }
}

使用此类,您可以将操作编码为

return Failable.of(
      values.stream().filter(value -> value.getOrder("order") == order).findAny(),() -> new RuntimeException("Could not find value of order " + order))
   .map(Attribute::getId,()->new RuntimeException("Value of order "+order+" has no id"))
   .map(Id::getName,()->new RuntimeException(
        "Could get the id but not the localized id of the value of order " + order)).get();

猜你在找的Java相关文章