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)我在这里遗漏了什么吗?可选是真的错过了这个 编辑:现在在我看来,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();
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
