首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Optional.ifAbsentThrow()?

Optional.ifAbsentThrow()?
EN

Stack Overflow用户
提问于 2015-02-01 22:35:20
回答 3查看 9K关注 0票数 7

假设我需要找到某个orderorder,然后得到它的id,然后得到它的localized-id。如果我做不到,我想抛出和例外:

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
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; 
                    };
    }

我就是这样用的:

代码语言:javascript
复制
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显然不能很好地处理空值,如果将它们混合在一起,就会变得冗长。然而,在现实世界中,我发现很难处理这个要么全是零的命题:一些代码被翻译成选项,而另一些则使用可空值。为了帮助我把它们混在一起,并且只在必要的时候将零符号重构成选项,我相信我将使用下面的GetNonNull类,建立在我从这个页面中的@Alex和@Holgers的答案中获得的知识的基础上。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-02-03 00:52:18

基于本页中从@Alex和@Holgers答案中获得的知识,我开发了以下GetNonNull类,重点是可读性:

代码语言:javascript
复制
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名称意味着最终结果永远不会为null。

将其与替代命令式代码进行比较:

代码语言:javascript
复制
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;

您也可以返回一个Optional,而不是抛出

代码语言:javascript
复制
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.

或者您可以返回一个非null默认值:

代码语言:javascript
复制
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不可知论的,也就是说,如果初始值是常规的可空值,而不是Optional,则不会发生任何变化。

代码语言:javascript
复制
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();

您也可以使用它作为一个简单的函数获取默认值成语。这是:

代码语言:javascript
复制
Value value = ...;
if (value != null) return value;
else if (default != null) return default;
else throw new NullPointerExeption();

可以写成:

代码语言:javascript
复制
// 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);

这是:

代码语言:javascript
复制
Optional<Value> value = ...;
if (value.isPresent()) return value;
else if (default != null) return default;
else throw new NullPointerExeption();

也可以写成完全相同的文字:

代码语言:javascript
复制
return GetNonNull.getOrDefault(value, default);

由于GetNonNull类与not和Optionals兼容,如果一些使用可空值的遗留命令式代码稍后被重构为使用选项,则不需要更改GetNonNull用法。

下面是:

代码语言:javascript
复制
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);
        }
    }
票数 3
EN

Stack Overflow用户

发布于 2015-02-01 23:10:43

  1. 是的,Optional没有一个ifAbsentThrow方法,如果它存在,它会返回Optional。最近的是orElseThrow,它从可选的返回值。
  2. 因为你的方式实际上行不通,所以肯定有一个更好的方法。

它不能工作,因为这是Optional#filter的实现

代码语言:javascript
复制
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应用映射函数之后重新包装结果。

代码语言:javascript
复制
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#getIdId#getName更改为返回Optionals而不是null。然后看起来是这样的:

代码语言:javascript
复制
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重新包装返回值,并且它让调用这些方法的其他人知道返回值是可选的,但是如果您不能更改它们,那么第一种方法就能正常工作。

票数 6
EN

Stack Overflow用户

发布于 2015-02-04 00:55:26

假设的ifAbsentThrow(...)方法可以用现有的Optional方法来表示,如下所示:

代码语言:javascript
复制
.map(Optional::of).orElseThrow(...)

然后,您的原始示例如下:

代码语言:javascript
复制
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));
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28268751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档