在 Java 中将列表或单个列表项作为方法参数传递是否更有效?

Is it more efficient to pass a List or individual List Items as method arguments in Java?

假设我有一个包含 100 个字符串的列表。以下两种方法在性能上是否存在差异(或任何其他差异)

1.

List<String> myList = Arrays.asList("s1", "s2", "s3"....."s100");        
foo(myList);

private void foo(List<String> myList) {
    // logic to choose 2 strings from the list
    //do something with -- str1 and str2
}

2.

List<String> myList = Arrays.asList("s1", "s2", "s3"....."s100");    
// logic to choose 2 strings from the list
foo(str1, str2);

private void foo(String myStr1, String myStr2) {
    //do something with -- myStr1 and myStr2
}

由于 Java 传递了列表或单个字符串的引用(作为值),我假设这些参数将只保留(副本)references/addresses。所以我倾向于通过整个列表。

上面将是一个实用方法,我想将 'logic to choose 2 strings from the list' 放在 foo 方法中,这样调用者就不必在调用之前重复该逻辑;但我担心发送一个大列表作为参数。

感谢您的帮助。

** 编辑 :** 是的,我正在寻找性能问题。

List<String> 可能不是正确的例子。将其视为 Map<String,Long>(城市、温度)。逻辑是始终选择芝加哥和洛杉矶,foo 将根据温度进行操作。请注意,此逻辑将始终相同,调用者只需重复方法 #2 中的相同代码。

我建议您忽略潜在的性能差异(在这种情况下可以忽略不计)并完全关注代码的清晰度。换句话说,问题不在于哪个更有效,而是哪个能更好地反映您调用的方法的意图。如果 foo 是一种自然需要两个参数的方法(例如 storeFullName),那么它应该传递两个参数。如果它自然期望 select 列表中的两个值(例如 printTwoLongestStrings),那么它应该采用一个集合。

你也可以考虑给每个方法一个single responsibility的原则。在那种情况下,使用单独的方法 selecting 两个值并用它们做一些事情可能是有意义的:

Pair<String, String> longestPair = getTwoLongestStrings(list);
printStrings(longestPair);

** 编辑 **

您的问题已阐明您特别关注性能,并且您提供了有关用例的更多详细信息。具体来说,您是在询问将一个列表或两个值传递给方法时性能是否存在差异。是,有一点不同。我 运行 尝试使用两个字符串参数和一个列表调用一个空函数 100 亿次。列表调用用了 24 秒,单独的参数调用用了 13 秒。其他物理硬件可能会显示不同的结果。也有可能 JVM 优化并没有使它成为一个公平的测试。

public class PerfTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b");
        long time1 = System.currentTimeMillis();
        for (long i = 0; i < 1E10; i++) {
            func1("a", "b");
        }
        long time2 = System.currentTimeMillis();
        for (long i = 0; i < 1E10; i++) {
            func2(list);
        }
        System.out.println((time2 - time1) + "/" + (System.currentTimeMillis() - time2));
    }

    private static void func1(String s1, String s2) { }
    private static void func2(List<String> sl) { }
}

但是我上面的回答仍然有效:如果你调用一个函数 100 亿次,那么它可能值得优化,但更好的做法是从关注清晰度开始,然后使用分析来关注代码调整工作如果需要的话。

如果方法对列表本身感兴趣,而不仅仅是它的项目,我建议只使用 List 作为参数,例如它计划对其进行修改。

对于其他情况,如果你有固定数量的参数,你应该让每个参数都是它自己的参数。但是您的案例表明您有可变数量的参数。为此,您还可以使用可变参数:

private void foo(String... strings) {
    // `strings` is an array now
}

这样做的好处是调用者可以选择使用单个对象或数组调用您的函数:

foo("Hello", "World");

或这个

String[] strings = new String[]{"Hello", "World"};
foo(strings);

甚至这个:

List<String> strings = ...;
foo(strings.toArray(new String[0]));

如果您担心将列表转换为数组,请坚持传递列表本身。

我想你问的是 List 参数是否通过引用传递。这是。在编译后的机器代码中,对于列表参数,只有一个指向列表对象实例的指针将被传递给函数。没有理由担心有一个大列表作为参数。