调用该函数两次与存储输出并在Java中使用它

时间:2014-05-17 14:25:10

标签: java performance function-calls

假设我有一个boolean函数isCorrect(Set<Integer>) 函数的参数由另一个函数buildSet()计算。

哪一项在时间和空间效率方面都更好?

Set<Integer> set = buildSet();
if(isCorrect(set))
    doSomethingWith(set);

if(isCorrect(buildSet()))
    doSomethingWith(buildSet());

4 个答案:

答案 0 :(得分:4)

第一种方法更好,我不认为这是一个意见问题。当你已经有了它的结果时,不要浪费两次相同的功能。当然,我假设buildSet()没有任何必要的副作用。

  

哪一项在时间和空间效率方面都更好?

就时间而言,您在第一个片段中构建了一次,在第二个片段中构建了两次,因此大概需要更长时间。在空间方面,可能没有区别。但是,您似乎在第二个片段中实例化了两个对象,而在您的第一个片段中只有一个(再次,我无法确定这一点,因为我不知道buildSet()是怎样的实现)。如果是这种情况并且你保留了这两个对象,那么第二个片段也将使用两倍的空间。

答案 1 :(得分:1)

答案是 - 这取决于。见下文:

  • 如果函数调用很耗时,则定义应该存储结果;
  • 存储结果可能会使代码的可读性稍差,尽管可读性不是客观指标;
  • 有时您可能希望确定第一次和第二次使用处理完全相同的对象。当您调用两次函数时,可能会得到不同的结果。这种情况通常称为竞争条件数据竞争,在大多数情况下,它会影响程序的正确性。

因此,总结一下:在大多数情况下,存储结果是有意义的。有时(但IMO不经常)它并不是真正的必要。

答案 2 :(得分:1)

虽然现有答案提供了很好的理由,为什么存储价值最好,但他们错过了我认为重要的一个(实际上,最重要的一个):在你的第二个例子中(两次运行该功能),你引入了潜在的竞争条件。

如果buildSet()依赖于外部因素(在任何非平凡的函数中很可能 - 并且可能在以后的更改中变为真实),则if检查之间的值可能会发生变化和第二个电话。这可能会创建一个微妙且难以找到的错误,当您在其他地方进行更改或某些事件在特定时间发生时,这些错误可能会变得可见。

这本身就是避免这种模式的一个很好的理由。

答案 3 :(得分:1)

通过从第二个示例(两个调用)转到第一个(一个调用),您将节省第二次调用buildSet在堆栈上的时间。如果该呼叫在10%的时间内在堆栈上,则您的加速将是100/90 = 1.11或11%的因子。如果它在50%的时间内处于堆栈中,则加速将是100/50 = 2或100%的因子。

你如何知道函数调用在堆栈中的时间长度? 它是包含挂钟的逐行

不是每个探查者都会告诉你这个。

  • 如果它只告诉你“自我时间”,而不是包容时间,则不会告诉你任何关于在函数调用中花费的时间。
  • 如果它只通过功能告诉你,而不是按行,你无法判断第二个调用是否是问题(而不是第一个)。
  • 如果它只是一个“CPU-profiler”,那么如果在buildSet函数或应用程序的其他地方有任何I / O,睡眠或锁定等待,那么分析器的行为就像它没有存在。
  • 如果它没有告诉你百分比,而只是毫秒或通话次数,那么你必须做数学计算,以确定通话中总时间的百分比是多少。
  • 调用图表没有告诉你,“火焰图”没有告诉你,时间表没有告诉你,等等。

告诉你的是Zoom。 其他人可能,如果你能弄明白如何告诉他们该做什么。 我和很多人使用的方法是random pausing