【问题标题】:Throw an exception if an Optional<> is present如果存在 Optional<> 则抛出异常
【发布时间】:2015-02-19 00:43:26
【问题描述】:

假设我想查看一个对象是否存在于流中,如果不存在,则抛出异常。我可以做到这一点的一种方法是使用orElseThrow 方法:

List<String> values = new ArrayList<>();
values.add("one");
//values.add("two");  // exception thrown
values.add("three");
String two = values.stream()
        .filter(s -> s.equals("two"))
        .findAny()
        .orElseThrow(() -> new RuntimeException("not found"));

反过来呢?如果我想在找到任何匹配项时抛出异常:

String two = values.stream()
        .filter(s -> s.equals("two"))
        .findAny()
        .ifPresentThrow(() -> new RuntimeException("not found"));

我可以只存储Optional,然后再检查isPresent

Optional<String> two = values.stream()
        .filter(s -> s.equals("two"))
        .findAny();
if (two.isPresent()) {
    throw new RuntimeException("not found");
}

有没有办法实现这种ifPresentThrow 的行为?尝试以这种方式投掷是一种不好的做法吗?

【问题讨论】:

  • orElseThrow 的要点是在值不存在时将值转换为具有错误处理的非可选值。由于您感兴趣的是该值是否存在,为什么不使用为此目的设计的方法:isPresent

标签: java java-8


【解决方案1】:

如果您的过滤器发现任何内容,您可以使用 ifPresent() 调用引发异常:

    values.stream()
            .filter("two"::equals)
            .findAny()
            .ifPresent(s -> {
                throw new RuntimeException("found");
            });

【讨论】:

  • 不能在ifPresent方法中抛出。
  • 是的,它可以 - 执行以下操作。 Optional.of(1).ifPresent(s -&gt; {throw new RuntimeException("oh look an exception");});
  • 这种方式只能抛出RuntimeException
  • 任何未经检查的异常都可以这样抛出
  • 以及Error的派生词
【解决方案2】:

由于您只关心是否找到了匹配项,而不是实际找到的内容,因此您可以为此使用anyMatch,而您根本不需要使用Optional

if (values.stream().anyMatch(s -> s.equals("two"))) {
    throw new RuntimeException("two was found");
}

【讨论】:

  • .anyMatch("two"::equals)
  • @Misha:这是 lambda 表达式更高效的罕见情况之一,因为它不捕获任何值(因为 "two" 是编译时常量)。相反,方法引用将始终捕获要在其上调用方法的实例。
  • 我知道@Holger 是对的,但我不得不承认@Misha 的"two"::equals 是一个非常好的语法。很难说不,以获得一些非秒的性能:-)
  • @Edwin Dalorzo:我并不反对使用替代语法。我只是想强调,虽然有时人们倾向于使用方法引用来提高效率,但这并不适用于此。因此,如果您认为方法引用的语法更好,并且对于 null 值的不同语义没有问题,您可以忽略小的效率差异。
  • @Holger lambda 真的比方法参考更有效吗? lambda 必须通过包含 lambda 主体的合成方法调用,然后调用 equals。方法引用捕获接收器实例,但随后它直接调用equals。对我来说不明显哪个更有效。 (我没有对此进行基准测试。)
【解决方案3】:
userOptional.ifPresent(user1 -> {throw new AlreadyExistsException("Email already exist");});

这里中括号是强制的,否则显示编译时异常

{throw new AlreadyExistsException("Email already exist");}

public class AlreadyExistsException extends RuntimeException

并且异常类必须扩展运行时异常

【讨论】:

    猜你喜欢
    • 2017-01-12
    • 2018-03-03
    • 2011-10-18
    • 1970-01-01
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多