4

It's been a while since I last used Java, as I'm primarily a C# developer. To get back into the game, I was working on a very simple application to touch on most of the key features of the language. I ran across the following problem:

for (Player player : teamRed.getPlayers()) {
    System.out.format("> %s\n", player.getName());
}

Where getPlayers() is defined as follows:

public Iterable<Player> getPlayers() {
    return Collections.unmodifiableList(this.players);
}

At some point in the past, either C# or Java had a performance issue when you used a getter in your for each like this, as it would execute the method every iteration. I cannot find anything about this anymore, so I wonder:

Has Java ever been subject to this issue, or was it the case for C# only?

Personally, I feel the compiler should be smart enough to optimize this properly and actually store the result of getPlayers in a temporary variable before iterating over it. But if not, I have no trouble helping the compiler a hand :P

Lennard Fonteijn
  • 2,561
  • 2
  • 24
  • 39
  • 3
    Look up the enhanced for statement [in the language spec](https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.14.2), look for "The enhanced for statement is equivalent to a basic for statement of the form". You will find that the `getPlayers()` method is called just once, by specification. – Andy Turner Aug 25 '16 at 16:21
  • 2
    I disagree with this being a duplicate. I recall it was specifically related to using a method to retrieve the list you want to iterate over. The linked question uses direct access to a defined array. – Lennard Fonteijn Aug 25 '16 at 16:21
  • 1
    I don't remember Java ever having such a problem (since before 1.2) and I'm having a hard time believing C# would have suffered from such an elementary oversight as well. – Kayaman Aug 25 '16 at 16:26
  • @LennardFonteijn That's why it says *possible* duplicate :) – Yassin Hajaj Aug 25 '16 at 16:31
  • Note that wrapping `this.players` in an unmodifiable list is mostly redundant: it just means that the list can't be modified through the returned reference - but it could be through anything holding a reference to the list directly, like the instance owning the players list. You may as well just return the list directly - the return type is `Iterable`, which is itself unmodifiable. (Or return a copy of the list). – Andy Turner Aug 25 '16 at 16:32
  • @Kayaman Reading all comments now, I think this was the case when you iterated over a LINQ query in C# that was not persisted yet (`ToList()`, `ToArray()`), not Java as you mention :) – Lennard Fonteijn Aug 25 '16 at 16:33
  • @AndyTurner The `getPlayers()` is part of a class that does not expose the players-list by any other means, it's completely private (and final for that matter). I purposely return an unmodifiable list to force people to use the `addPlayer()` method, also part of the class :) – Lennard Fonteijn Aug 25 '16 at 16:35

1 Answers1

3

The compiler will store the iterator (from calling the iterator() method on the Iterable) that it loops over, so the getPlayers() method will only be called once. You could observe this using the below adaptation of getPlayers()

public Iterable<Player> getPlayers() {
    System.out.println("getPlayers() called");
    return Collections.unmodifiableList(this.players);
}

When running your first code snippet, "getPlayers() called" would only be printed once.

Check the Iterable docs for more detail (notably the iterator() method): https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html

SamTebbs33
  • 5,507
  • 3
  • 22
  • 44