Java中变量参数方法的性能

我有一个关于Java中具有可变数量参数的方法的性能的问题。

说我有以下两种选择:

public static final boolean isIn(int i, int v1, int v2) { return (v1 == i) || (v2 == i); } public static final boolean isIn(int i, int... values) { for (int v : values) { if (i == v) { return true; } } return false; } 

现在,当我有第一种方法的版本达到20,30或甚至50个参数时,主要问题出现了。 现在那只会伤到眼睛。 好的,这是遗留代码,我想用唯一的一个变量参数方法替换所有代码。

知道对性能有什么影响吗? 编译器是否有机会对第二种方法进行一些优化,以便它或多或少类似于第一种forms?

编辑:好的,也许我不够清楚。 我有50个参数的方法没有性能问题。 彼得·劳雷说,这只是可读性。 如果我切换到具有可变数量参数的新方法,我想知道性能问题
换句话说:如果你关心性能,最好的方法是什么 ? 有50个参数的方法或只有一个带变量参数的方法?

我有同样的问题,转向实验。

 public class ArgTest { int summation(int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; } int summationVArgs(int... args) { int sum = 0; for (int arg : args) { sum += arg; } return sum; } final static public int META_ITERATIONS = 200; final static public int ITERATIONS = 1000000; static public void main(String[] args) { final ArgTest at = new ArgTest(); for (int loop = 0; loop < META_ITERATIONS; loop++) { int sum = 0; final long fixedStart = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { sum += at.summation(2312, 45569, -9816, 19122, 4991, 901776); } final long fixedEnd = System.currentTimeMillis(); final long vargStart = fixedEnd; for (int i = 0; i < ITERATIONS; i++) { sum += at.summationVArgs(2312, 45569, -9816, 19122, 4991, 901776); } final long vargEnd = System.currentTimeMillis(); System.out.printf("%03d:%d Fixed-Args: %d ms\n", loop+1, ITERATIONS, fixedEnd - fixedStart); System.out.printf("%03d:%d Vargs-Args: %d ms\n", loop+1, ITERATIONS, vargEnd - vargStart); } System.exit(0); } } 

如果在现代JVM(此处为1.8.0_20)上运行此代码,您将看到可变数量的参数会导致性能开销,也可能导致内存消耗。

我只发布前25次运行:

 001:1000000 Fixed-Args: 16 ms 001:1000000 Vargs-Args: 45 ms 002:1000000 Fixed-Args: 13 ms 002:1000000 Vargs-Args: 32 ms 003:1000000 Fixed-Args: 0 ms 003:1000000 Vargs-Args: 27 ms 004:1000000 Fixed-Args: 0 ms 004:1000000 Vargs-Args: 22 ms 005:1000000 Fixed-Args: 0 ms 005:1000000 Vargs-Args: 38 ms 006:1000000 Fixed-Args: 0 ms 006:1000000 Vargs-Args: 11 ms 007:1000000 Fixed-Args: 0 ms 007:1000000 Vargs-Args: 17 ms 008:1000000 Fixed-Args: 0 ms 008:1000000 Vargs-Args: 40 ms 009:1000000 Fixed-Args: 0 ms 009:1000000 Vargs-Args: 89 ms 010:1000000 Fixed-Args: 0 ms 010:1000000 Vargs-Args: 21 ms 011:1000000 Fixed-Args: 0 ms 011:1000000 Vargs-Args: 16 ms 012:1000000 Fixed-Args: 0 ms 012:1000000 Vargs-Args: 26 ms 013:1000000 Fixed-Args: 0 ms 013:1000000 Vargs-Args: 7 ms 014:1000000 Fixed-Args: 0 ms 014:1000000 Vargs-Args: 7 ms 015:1000000 Fixed-Args: 0 ms 015:1000000 Vargs-Args: 6 ms 016:1000000 Fixed-Args: 0 ms 016:1000000 Vargs-Args: 141 ms 017:1000000 Fixed-Args: 0 ms 017:1000000 Vargs-Args: 139 ms 018:1000000 Fixed-Args: 0 ms 018:1000000 Vargs-Args: 106 ms 019:1000000 Fixed-Args: 0 ms 019:1000000 Vargs-Args: 70 ms 020:1000000 Fixed-Args: 0 ms 020:1000000 Vargs-Args: 6 ms 021:1000000 Fixed-Args: 0 ms 021:1000000 Vargs-Args: 5 ms 022:1000000 Fixed-Args: 0 ms 022:1000000 Vargs-Args: 6 ms 023:1000000 Fixed-Args: 0 ms 023:1000000 Vargs-Args: 12 ms 024:1000000 Fixed-Args: 0 ms 024:1000000 Vargs-Args: 37 ms 025:1000000 Fixed-Args: 0 ms 025:1000000 Vargs-Args: 12 ms ... 

即使在最好的时候,Vargs-Args也从未降到0ms。

编译器旁边没有优化。 JVM可以优化代码,但这两种方法不会执行彼此相似的任何操作。 如果您有像isIn(i, 1,2,3,4,5,6,7,8,9 /* plus 40 more */)的代码行,那么您需要担心的不仅仅是性能问题恕我直言。 我先担心可读性。

如果你担心性能将参数作为int[]传递,可以重用。

BTW查找大量int值的最有效方法是使用类似TIntHashSet的Set

如果您有分析器输出,请回来说这是一个问题。 在那之前,它是不成熟的优化。

致@Canonical Chris

我认为你测试中的问题不是来自变量论证。 由于for loop ,函数sumationVArgs需要更多时间才能完成。

我创建了这个函数并添加到基准测试中

 int summationVArgs2(int... args) { return args[0] + args[1] + args[2] + args[3] + args[4] + args[5]; } 

这就是我所看到的:

 028:1000000 Fixed-Args: 0 ms 028:1000000 Vargs-Args: 12 ms 028:1000000 Vargs2-Args2: 0 ms 

函数“summationVArgs”中的for loop被编译为比添加函数更多的操作。 它包含add operation以增加迭代器, check operation以检查条件和branch operation以循环和退出循环,并且除了分支操作以退出循环之外,它们都为每个循环执行一次。

对不起,我的英语不好。 我跳你可以理解我的英文:)

它将与您声明的相同

  isIn(int i, int[] values) { 

但是,在调用方法时,将变量打包起来会有一些小的开销

听说两个优化规则:

  • 不要优化
  • (仅限专家!)不要优化

换句话说,从性能的角度来看,这不是你应该关心的。