在性能方面,在 Java 中执行一个 for 多个操作或多个 fors 每个操作有什么影响?

Joã*_*itt 2 java time-complexity

我担心提高源代码的可读性,它涉及通过将庞大的方法分解为更小的(简洁的)方法来减少它们的大小。所以,简而言之,假设我有一个非常单一的方法,可以做很多不同的事情,例如:

public void verHugeMethod(List<Person> people) {
    for (Person person : people) {
        totalAge += person.getAge();
        totalHeight += person.getHeight();
        totalWeight += person.getWeight();
        // More calculations over class variables...
    }
}
Run Code Online (Sandbox Code Playgroud)

我想将方法​​更改为:

public void calculateTotalAge(List<Person> people) {
    for (Person person : people) {
        totalAge += person.getAge();
    }
}

public void calculateTotalHeight(List<Person> people) {
    for (Person person : people) {
        totalHeight += person.getHeight();
    }
}

public void calculateTotalWeight(List<Person> people) {
    for (Person person : people) {
        totalWeight += person.getWeight();
    }
}
// More calculations over class variables...
Run Code Online (Sandbox Code Playgroud)

我关心的是应用这种重构时的性能(时间和内存)。对于一小部分人来说,这当然不是问题,但我担心这个列表的渐近增长。

例如,对于更老式的for我可以看到以下影响:

// OPTION 1
public void method1() { // O(1) + O(3n)
    int i = 0; // O(1)
    while (int i < people.size()) { // O(n)
        doSomething(people.get(i)); // O(1)
        doAnotherThing(people.get(i)); // O(1)
        i++; // O(1)
    }
}

// OPTION 2
public void method1() { // O(2) + O(4n)
    method1(); // O(1) + O(2n)
    method2(); // O(1) + O(2n)
}
public void method2() { // O(1) + O(2n)
    int i = 0; // O(1)
    while (int i < people.size()) { // O(n)
        doSomething(people.get(i)); // O(1)
        i++; // O(1)
    }
}
public void method3() { // O(1) + O(2n)
    int i = 0; // O(1)
    while (int i < people.size()) { // O(n)
        doAnotherThing(people.get(i)); // O(1)
        i++; // O(1)
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道 Java 如何将foreach指令转换为iterables. 因此,我的问题是:

  1. Java 在执行或编译方面是否有一些优化?
  2. 我应该关心这种性能问题吗?

注意:我知道就渐近增长和 Big-O 表示法而言,我们应该忽略常量,但我只是想知道这种情况如何应用于 Java。

Ste*_*n C 5

如果您完成 big-O 分析,您将看到两个选项都减少到O(n). 它们具有相同的复杂性!

它们可能没有相同的性能,但复杂性和复杂性分析(和 Big-O 表示法)不是用于测量或预测性能的。实际上,对于足够小的 值,O(n)算法可能比算法执行得更好。O(1)n


Java 在执行或编译方面是否有一些优化?

是的。JIT 编译器做了很多优化(在运行时)。但是,我们无法预测选项 1 和选项 2 是否具有相同的性能。

我应该关心这种性能问题吗?

是和否。

这取决于性能是否/多少对您的项目很重要。 对于许多项目1,与其他事物相比,应用程序性能并不重要;例如满足所有功能要求,始终计算正确答案,不崩溃,不丢失更新等。

当性能是一个问题时,>this< 代码片段(在代码库中的数百、数千、数百万行中)不一定值得优化。并非所有代码都是平等的。如果这段代码只是偶尔执行,那么优化它对整体性能的影响可能很小。

标准的口头禅是避免过早优化。等到你的代码工作。然后创建一个基准来衡量应用程序在执行实际工作时的性能。然后分析运行基准测试的应用程序以找出代码的哪些部分是性能热点……并将优化工作集中在热点上。


1 - 关键是必须在项目的所有其他要求和限制的背景下考虑性能。如果您过早地在绩效上花费太多时间,您很可能会错过截止日期等。更不用说在优化错误代码上浪费精力了。