Optional.ifAbsentThrow()?
Optional.ifAbsentThrow()?
假设我需要找到某个order
的value
,然后得到它的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));
问题是异常不是很详细:它告诉我无法获取 localized-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
不存在,因为它是处理 null
值的一种方式,并且 Optional
是关于首先不使用 null
值。 Optional
显然不能很好地处理空值,如果混合使用它们会变得冗长。然而,在现实世界中,我发现很难处理这个全有或全无的命题:一些代码被转换为 Optionals,而其他代码仍然使用可为 null 的值。为了帮助我混合使用它们,并仅在必要时将可空值重构为可选值,我相信我将使用下面的 GetNonNull
class,基于我从本页的@Alex 和@Holgers 答案中获得的知识。
是的,Optional
没有 ifAbsentThrow
方法 return 是 Optional
如果存在的话。最接近的是 orElseThrow
,其中 return 是可选值。
既然你的方法实际上行不通,肯定有更好的方法。
它不起作用,因为这是 Optional#filter
:
的实现
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
如您所见,如果 Predicate
不存在,它不会使用它,因此您的 filter
什么都不做。
一种方法是使用 orElseThrow
,然后在使用 ofNullable
:
应用映射函数后重新包装结果
Optional<Attribute> o = //get your first optional from the stream.
return Optional.ofNullable(Optional.ofNullable(
o.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId())
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName())
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
如果您认为可读性更好,也可以将其分解为单独的语句。
另一种方法是将 Attribute#getId
和 Id#getName
更改为 return Optional
s 而不是 null。然后它看起来像这样:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId()
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName()
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
我更喜欢这种方式,因为你不需要用 ofNullable
重新包装 return 值,它让其他调用这些方法的人知道 return 值是可选的,但如果你不能改变它们,那么第一种方法就可以了。
Optional
用于封装可能不存在的值。如果你执行像 ifAbsentThrow
这样的操作,那么将值作为 Optional
携带是没有意义的,因为你已经知道它在正常完成时不会不存在。所以 orElseThrow
做你想要的,但是 returns 一个普通的对象,因为它不再是 可选的 。
当然,你可以apply
一个普通对象的函数,然后将其结果再次包装成Optional
,如,但问问你自己这是否真的是一个改进通过简单的代码:
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,R> f, 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()));
}
}
使用此 class,您可以将您的操作编码为
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();
根据我从本页的@Alex 和@Holgers 回答中获得的知识,
我开发了以下 GetNonNull
class,重点是可读性:
Optional<Value> value = values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny();
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
我觉得这个功能代码非常容易阅读,它把所有的异常处理代码集中在一起(不需要
添加 orElseThrow
到流的末尾)。 GetNonNull
名称暗示最终结果永远不会为空。
将其与替代命令式代码进行比较:
if (valor == null) throw new RuntimeException("Got no value.");
Attribute attribute = valor.getAttribute();
if (attribute == null) throw new RuntimeException("Got value, but no attribute.");
Id id = attribute.getId();
if (id == null) throw new RuntimeException("Got value and attribute, but no id.");
String localizedId = id.getLocalizedId();
if (localizedId == null) throw new RuntimeException("Got value, attribute and id, but no localized id.");
return localizedId;
除了投掷,你还可以 return 一个 Optional
:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOptional(Id::getLocalizedId); // Changed here.
或者您可以 return 非 null
默认值:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOrDefault(Id::getLocalizedId, "DEFAULT"); // Changed here.
它也是 Optional
/null
不可知论者,也就是说,如果初始值是一个常规的可为 null 的值而不是 Optional
:
,则没有任何变化
Value value = ...; // Not an Optional.
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
您也可以将其用作简单的函数式获取默认值习惯用法。这个:
Value value = ...;
if (value != null) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
可以写成:
// Shorter and more readable then Optional.ofNullable(value).orElse(default).
// Also not the same, because here a NullPointerException is raised if default is null.
return GetNonNull.getOrDefault(value, default);
还有这个:
Optional<Value> value = ...;
if (value.isPresent()) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
也可以完全一样写成:
return GetNonNull.getOrDefault(value, default);
由于 GetNonNull
class 与 nullables 和 Optionals 兼容,如果某些遗留命令
使用可空值的代码稍后会重构为使用 Optionals,GetNonNull
用法不需要更改。
这里是:
public final class GetNonNull<T, E extends Throwable> {
private final T value;
private final E failure;
private GetNonNull(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> Optional<R> getOptional(Function<T, R> f) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
return Optional.ofNullable(result);
}
return Optional.empty();
}
public static <R> R getOrDefault(R o1, Supplier<R> supplier) {
if (o1 != null) return o1;
R result = supplier.get();
if (result != null) return result;
else throw new NullPointerException();
}
public static <R> R getOrDefault(R o1, R o2) {
if (o1 != null) return o1;
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public static <R> R getOrDefault(Optional<R> o1, R o2) {
if (o1.isPresent()) return o1.get();
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public <R> R getOrDefault(Function<T, R> f, R o) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
if (result != null) return result;
else return o;
}
return o;
}
public <R> GetNonNull<R, E> mapOrThrow(Function<T, R> f, Supplier<E> s) {
if (value != null) {
R result = f.apply(value);
return new GetNonNull<>(result, (result != null) ? null : s.get());
}
return (GetNonNull)this;
}
public static <T, E extends Throwable> GetNonNull<T, E> getOrThrow(Optional<T> o, Supplier<E> s) {
return o.map(t -> new GetNonNull<>(t, (E)null)).orElseGet(() -> new GetNonNull<>(null, s.get()));
}
public static <T, E extends Throwable> GetNonNull<T, E> mapOrThrow(T o, Supplier<E> s) {
return getOrThrow(Optional.ofNullable(o), s);
}
}
假设的ifAbsentThrow(...)
方法可以用Optional
的现有方法表示如下:
.map(Optional::of).orElseThrow(...)
那么你原来的例子就变成了:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.map(Optional::of)
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.map(Attribute::getId)
.map(Optional::of)
.orElseThrow(() -> 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));
假设我需要找到某个order
的value
,然后得到它的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));
问题是异常不是很详细:它告诉我无法获取 localized-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
不存在,因为它是处理 null
值的一种方式,并且 Optional
是关于首先不使用 null
值。 Optional
显然不能很好地处理空值,如果混合使用它们会变得冗长。然而,在现实世界中,我发现很难处理这个全有或全无的命题:一些代码被转换为 Optionals,而其他代码仍然使用可为 null 的值。为了帮助我混合使用它们,并仅在必要时将可空值重构为可选值,我相信我将使用下面的 GetNonNull
class,基于我从本页的@Alex 和@Holgers 答案中获得的知识。
是的,
Optional
没有ifAbsentThrow
方法 return 是Optional
如果存在的话。最接近的是orElseThrow
,其中 return 是可选值。既然你的方法实际上行不通,肯定有更好的方法。
它不起作用,因为这是 Optional#filter
:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
如您所见,如果 Predicate
不存在,它不会使用它,因此您的 filter
什么都不做。
一种方法是使用 orElseThrow
,然后在使用 ofNullable
:
Optional<Attribute> o = //get your first optional from the stream.
return Optional.ofNullable(Optional.ofNullable(
o.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId())
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName())
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
如果您认为可读性更好,也可以将其分解为单独的语句。
另一种方法是将 Attribute#getId
和 Id#getName
更改为 return Optional
s 而不是 null。然后它看起来像这样:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId()
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName()
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
我更喜欢这种方式,因为你不需要用 ofNullable
重新包装 return 值,它让其他调用这些方法的人知道 return 值是可选的,但如果你不能改变它们,那么第一种方法就可以了。
Optional
用于封装可能不存在的值。如果你执行像 ifAbsentThrow
这样的操作,那么将值作为 Optional
携带是没有意义的,因为你已经知道它在正常完成时不会不存在。所以 orElseThrow
做你想要的,但是 returns 一个普通的对象,因为它不再是 可选的 。
当然,你可以apply
一个普通对象的函数,然后将其结果再次包装成Optional
,如
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,R> f, 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()));
}
}
使用此 class,您可以将您的操作编码为
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();
根据我从本页的@Alex 和@Holgers 回答中获得的知识,
我开发了以下 GetNonNull
class,重点是可读性:
Optional<Value> value = values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny();
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
我觉得这个功能代码非常容易阅读,它把所有的异常处理代码集中在一起(不需要
添加 orElseThrow
到流的末尾)。 GetNonNull
名称暗示最终结果永远不会为空。
将其与替代命令式代码进行比较:
if (valor == null) throw new RuntimeException("Got no value.");
Attribute attribute = valor.getAttribute();
if (attribute == null) throw new RuntimeException("Got value, but no attribute.");
Id id = attribute.getId();
if (id == null) throw new RuntimeException("Got value and attribute, but no id.");
String localizedId = id.getLocalizedId();
if (localizedId == null) throw new RuntimeException("Got value, attribute and id, but no localized id.");
return localizedId;
除了投掷,你还可以 return 一个 Optional
:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOptional(Id::getLocalizedId); // Changed here.
或者您可以 return 非 null
默认值:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOrDefault(Id::getLocalizedId, "DEFAULT"); // Changed here.
它也是 Optional
/null
不可知论者,也就是说,如果初始值是一个常规的可为 null 的值而不是 Optional
:
Value value = ...; // Not an Optional.
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
您也可以将其用作简单的函数式获取默认值习惯用法。这个:
Value value = ...;
if (value != null) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
可以写成:
// Shorter and more readable then Optional.ofNullable(value).orElse(default).
// Also not the same, because here a NullPointerException is raised if default is null.
return GetNonNull.getOrDefault(value, default);
还有这个:
Optional<Value> value = ...;
if (value.isPresent()) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
也可以完全一样写成:
return GetNonNull.getOrDefault(value, default);
由于 GetNonNull
class 与 nullables 和 Optionals 兼容,如果某些遗留命令
使用可空值的代码稍后会重构为使用 Optionals,GetNonNull
用法不需要更改。
这里是:
public final class GetNonNull<T, E extends Throwable> {
private final T value;
private final E failure;
private GetNonNull(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> Optional<R> getOptional(Function<T, R> f) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
return Optional.ofNullable(result);
}
return Optional.empty();
}
public static <R> R getOrDefault(R o1, Supplier<R> supplier) {
if (o1 != null) return o1;
R result = supplier.get();
if (result != null) return result;
else throw new NullPointerException();
}
public static <R> R getOrDefault(R o1, R o2) {
if (o1 != null) return o1;
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public static <R> R getOrDefault(Optional<R> o1, R o2) {
if (o1.isPresent()) return o1.get();
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public <R> R getOrDefault(Function<T, R> f, R o) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
if (result != null) return result;
else return o;
}
return o;
}
public <R> GetNonNull<R, E> mapOrThrow(Function<T, R> f, Supplier<E> s) {
if (value != null) {
R result = f.apply(value);
return new GetNonNull<>(result, (result != null) ? null : s.get());
}
return (GetNonNull)this;
}
public static <T, E extends Throwable> GetNonNull<T, E> getOrThrow(Optional<T> o, Supplier<E> s) {
return o.map(t -> new GetNonNull<>(t, (E)null)).orElseGet(() -> new GetNonNull<>(null, s.get()));
}
public static <T, E extends Throwable> GetNonNull<T, E> mapOrThrow(T o, Supplier<E> s) {
return getOrThrow(Optional.ofNullable(o), s);
}
}
假设的ifAbsentThrow(...)
方法可以用Optional
的现有方法表示如下:
.map(Optional::of).orElseThrow(...)
那么你原来的例子就变成了:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.map(Optional::of)
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.map(Attribute::getId)
.map(Optional::of)
.orElseThrow(() -> 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));