【问题标题】:How to check whether value is not present or just has no value?如何检查价值是不存在还是没有价值?
【发布时间】:2020-09-28 07:50:39
【问题描述】:

我是 Java 新手,并且是可选的。这里我有一个未排序的素数数组。

List<Integer> primes = Arrays.asList(3, 7, 5, 2, 13, 11);
int getPrime()
{
 primes.sort(); //using Comparator
 return (primes.stream()
            .filter(prime -> prime>15)
            .findFirst()
            .orElseThrow(() -> new NoSuchElementException("No such number")));
}

案例 A:我想返回第一个素数 > 7 - 效果很好。

案例B:我想返回第一个素数> 15

案例C:列表为空/由于某种原因,它无法访问列表。

如果是 B & C ;抛出相同的 NoSuchElementException。完全无法获取与能够获取但无法获取有效号码之间是有区别的。

如何更改此代码而不使其过于复杂以至于无法检查这些情况?

【问题讨论】:

  • 为什么不在排序前检查primes.isEmpty()?您可以在方法的开始处抛出适当的异常,前提条件检查应该在哪里。
  • 我看不出有什么不同。给定一个带有素数的列表,找到一个满足特定条件的素数。如果列表为空,则列表不包含符合条件的数字

标签: java exception nullpointerexception null optional


【解决方案1】:

您可以先检查任何元素,否则抛出异常,然后它们会过滤流。

int getPrime() {
    if (primes.isEmpty()) 
        throw new NoSuchElementException("Empty list is given.")));

    primes.sort(); //using Comparator

    return (primes.stream()
            .filter(prime -> prime > 15)
            .findFirst()
            .orElseThrow(() -> new NoSuchElementException("Element could not be found.")));
}

【讨论】:

  • 有一个isEmpty API 需要首先检查。
  • 此外,没有必要对列表进行排序(通常不鼓励为搜索操作修改输入集合)。你可以简单地使用return primes.stream() .filter(prime -&gt; prime &gt; 15) .min​(Comparator.naturalOrder()) .orElseThrow(() -&gt; new NoSuchElementException("Element could not be found."));
【解决方案2】:

你可以试试

if(primes.size() == 0) throw new MyExcceptionForFailedToFetch();

但你最好在获取代码时抛出异常。

【讨论】:

  • primes.size() == 0primes.isEmpty()...
【解决方案3】:

我不同意你的说法:

完全无法获取和能够获取之间存在差异 获取但没有得到一个有效的数字。

让我解释一下。

异常准则是方法契约内的行为应产生适当的返回值,而方法无法履行其契约的情况会导致异常。

那么,你的方法的“契约”是什么?您希望它搜索大于给定阈值的最小素数(至少,我是这么理解的)。我的推理就是基于这种抽象。

从数学上讲,总会存在这样一个质数,因此该合约的理想实现总会有答案。给定的实现有其局限性,因此在某些情况下它无法履行合同。在这些情况下,抛出异常是正确的做法。

您列出了两种不同的失败案例,primes 列表为空(或无法访问 - 一种罕见的情况已经抛出了自己的异常,因此我们可以在接下来的讨论中忽略它)与列表不包含一个大于你的阈值的素数。

两个我,这个区别并不重要。在这两种情况下,primes 列表对于请求的阈值来说都太短了,零元素只是“太短”的极端情况。在这两种情况下,返回一个值都是错误的,相反,应该抛出一个异常,所以调用者知道这个问题没有得到回答。你已经在这样做了。

调用者可能对失败的原因感兴趣(大多数时候,他只需要知道调用失败而不关心为什么)。这在异常类型及其消息中表示。据我了解,NoSuchElementException 不是最能表达失败原因的选择。 documented 是“由各种访问器方法抛出以指示所请求的元素不存在”。在搜索大于给定阈值的最小素数的上下文中,我可以想象应用该规范的两种不同解释:

  • “元素”表示数学素数。正如我们所说,它肯定存在,所以我们会得出一个错误的陈述“抛出......表明下一个更高的素数不存在。”
  • “元素”表示素数列表中的元素。那么该陈述是正确的(“抛出......以指示素数列表中的适当元素不存在”)。但它与调用者无关,因为它讨论了一些调用者甚至不应该知道的实现细节:该方法在其计算中使用预定义的素数列表这一事实。

我更喜欢UnsupportedOperationExceptiondocumented 作为“抛出以表明不支持请求的操作。”,在我看来,这与失败完全匹配。

所以,我在你的代码中唯一要改变的就是抛出 new UnsupportedOperationException("primes list too short") 而不是 NoSuchElementException

【讨论】:

  • 非常好的信息,但我有两个问题是“你不认为你在对待NoSuchElementException 反对普遍真理,而不仅仅是反对给定列表吗?”而且,“在业务逻辑中始终包含通用真理边界真的值得吗?”
  • 这一切都取决于一个清楚地理解的合同,我已经在我的回答中记录了我对合同的理解:“搜索大于给定阈值的最小素数”。那么,给定的列表只是一个(有缺陷的)实现细节,不应成为合同的一部分。
  • 当你不能从一个方法返回真正的答案时,抛出一个适当的异常。唉,即使是像整数加法这样的基本操作也无法遵循该规则,并且在溢出的情况下会产生无意义的结果,而不是抛出异常。
  • @miiiiii 我会详细说明。
【解决方案4】:

我希望这可以在不使用流的情况下解决您的问题。

public static void main(String[] args) {
        List<Integer> primes = Arrays.asList(3, 7, 5, 2, 13, 11);
        if(!primes.isEmpty()) {
             Collections.sort(primes);
             for(int i : primes) {
                 if(i > 15) {
                     System.out.println(i);
                         break;
                 }
             }
        }else {
            System.out.println("Empty list is given");
        }
    }

【讨论】:

  • 我不得不投反对票,因为这不如 OP 的版本,而且绝不回答问题。算法可能没问题,但没有打包成有返回值或异常的方法。
  • 随时改进您的答案!
猜你喜欢
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-01
  • 2011-02-05
  • 1970-01-01
相关资源
最近更新 更多