Java如何在for循环中使用getter处理?

问题描述 投票:1回答:4

例如,如果我有以下for循环声明。

for(Foo f : fooService.getFooList()){}

首先调用getter并将其分配给临时List<Foo> fooList = fooService.getFooList();或者使用getter inline是否更有效?

java for-loop
4个回答
1
投票

在这个特定的情况下,使用foreach循环,我希望你的代码将编译成这样的东西:

Iterator<Foo> it = fooService.getFooList().iterator();
while (it.hasNext()) {
    Foo foo = it.next();
    // ...
}

所以在这种情况下,它没有什么区别。

但是,如果您使用不同类型的循环,那么它可能会有所不同。例如:

for(int i = 0; i < fooService.getFooList().size(); i++){
    Foo foo = fooService.getFooList().get(i);
    // ...
}

如果您的列表暴露于外部修改,那么编译器不太可能证明列表大小不会改变,因此它将调用getFooList().size()每次迭代以与i进行比较,因此会有一些轻微的额外开销。

但请注意,如果列表大小发生变化,那么i < fooService.getFooList().size()就会反映出来。如果您意识到这一点,这将非常有用,但如果您不了解,则会很危险。

如果你知道列表大小不会改变那么你可以做这样的事情来消除这种开销(或者只是使用Iterator或增强for-each循环,如果你不需要索引):

List<Foo> fooList = fooService.getFooList();
final int fooListSize = fooList.size();
for(int i = 0; i < fooListSize ; i++){
    Foo foo = fooList.get(i);
    // ...
}

尽管如此,您可能更喜欢可读性而不是微优化。

但是,如果您的应用程序对运行时敏感,并且您的列表很大并且这些小检查正在累加,那么您可能希望执行类似上述操作。


1
投票

首先分配给List引用并不是更有效,但根据您尝试执行的操作,使用引用可能会有用。


1
投票

如果你担心的是fooService.getFooList()被称为n时代获得每个价值f无视这个想法。这会调用getFooList()一次并迭代其结果。

例如,在以下snippet中:

class Ideone
{
    private static List<String> list = Arrays.asList("A", "B", "C");

    public static void main (String[] args) throws java.lang.Exception
    {
        for(String f : getFooList()){
           System.out.println(f);
        }
    }

    private static List<String> getFooList() {
        System.out.println("getFooList called");
        return list;
    }
}

getFooList called只打印一次,表示方法getFooList()仅由for循环调用一次。之后,它打印ABC,迭代从方法invokation获得的元素。

因此,就效率而言,直接调用getter或将其分配给变量并使用它来执行迭代是相同的。


0
投票

它完全一样。 getter被调用一次,而不是在完成每个循环之前。如果需要,将其分配给变量,否则没有必要。

仅供参考:在幕后,List本身不会被使用,而是它的Iterator

因此,你的for循环可以这样表达:

for (Iterator<Foo> i = fooService.getFooList(); i.hasNext();) {
    Foo foo= i.next();
}

有关更多信息,请参阅language specifications about the for loops

© www.soinside.com 2019 - 2024. All rights reserved.