tags:

views:

206

answers:

6
for (Player p : players) 
{
  p.addCard(deck.dealCard());
  p.addCard(deck.dealCard());
}

and

  for (int i = 0; i < players.size() ; i++)
{
    Player p = players.get(i);
    p.addCard(deck.dealCard());
    p.addCard(deck.dealCard());
}

The second code yeilds a null pointer exception, what can be done to make the bottom one equivalent ?

+2  A: 

Without knowing more details about Player, you could do the obvious thing and check that p is null before referencing it.

Justin Ethier
but p works fine in the first onewhy doesn't it work in the bottom instance (if the 2 statements are equal)?
Kevin Duke
@Kevin: That would be because the iterator [implicitly] used for the first snippet uses a different way to detect the "size".
mjv
@Kevin: Another possibility is that the iterator is filtering out `null` values in the "collection".
Stephen C
@Kevin: it will be good if instead of just start processing player, you try `if ( null != p ) { // code here `
Rakesh Juyal
+4  A: 

This is going to be a very wild guess: it might be possible that size() does not yield the number of Player in players but the total capacity of players. And, the Iterator for players iterates only over the allocated items.

So to answer your question from the title, those two snippets of code are not necessarily the same. The for-each structure uses an iterator and the creator of the code could have used any implementation he considered the most suitable for whatever players' type is.

Your for-each structure's for equivalent should look more like this:

for (Iterator<Player> i = players.iterator(); i.hasNext(); ){
        Player p = i.next();
        //... Your code here
}
Anzurio
I substituted this so it looked like the below code and it still yields the same null pointer exception. for (Iterator<Player> i = players.iterator(); i.hasNext(); { Player p = i.next(); p.addCard(deck.dealCard()); p.addCard(deck.dealCard());}
Kevin Duke
+1  A: 

Since the line p.addCard(deck.dealCard()); is throwing the NullPointerException then either

  1. p is null or
  2. deck is null or
  3. dealCard() method is causing the exception somewhere.

If at all possible you should use the Iterator for Collections.

Iterator<Player> iter = players.iterator();
while(iter.hasNext()){
   Player p = iter.next();
   p.addCard(deck.dealcard());
   //etc.
}
Vincent Ramdhanie
but why aren't they null in the first code snippet?
Kevin Duke
Is everything else in the code the same for both snippets?
Vincent Ramdhanie
yes, exactly the same, I'm just trying to rewrite this for-each loop to get a better understanding of it
Kevin Duke
+1  A: 

One scenario I can think of where a NullPointerException will be thrown in the second case is when addCard or dealCard somehow changes what players refer to (presumably neither modifies the content of players, because that would cause a ConcurrentModificationException in the first snippet).

Here's an example (please run this on your own if you have any doubts):

import java.util.*;

public class ForEachVS {
    static List<Integer> players;
    static void process(int i) {
        System.out.println(i);
        players = null;
    }
    public static void main(String args[]) {
        players = Arrays.asList(1,2,3);
        for (int p : players) {
            process(p);
        } // this processes 1,2,3
        players = Arrays.asList(1,2,3);
        for (int i = 0; i < players.size(); i++) {
            process(players.get(i));
        } // this processes 1, then throws NullPointerException
    }
}

So as you can see, the two constructs are actually NOT exactly equivalent. The essence of the above snippet is concisely presented here:

    int[] arr;

    arr = new int[5];
    for (int x : arr) {
        arr = null;
    }

    arr = new int[5];
    for (int i = 0; i < arr.length; i++) {
        arr = null;
    }

You will find out that the first loop went fine, while the second loop throws NullPointerException. So while it's true most of the time, the two constructs are not exactly 100% equivalent.

polygenelubricants
+1  A: 

I can see this happening if players is a custom java.lang.Iterable who's get() implementation is broken, or at any rate, behaves in an unexpected manner (different from java.util.List's behavior).

Other that that, the only thing I can think of is that something you're not showing us in your code is causing something to go terribly wrong.

What happens if you do this?

for (Iterator<Player> playerIter = players.iterator(); playerIter.hasNext();) 
{
  Player p = playerIter.next();
  p.addCard(deck.dealCard());
  p.addCard(deck.dealCard());
}

Edit:

Just read AZ's response, and it's definitely possible that it's size() that has the odd behavior as well.

Jack Leow
It says: "next() in java.util.Iterator cannot be applied to (int)"
Kevin Duke
@Kevin - change that to `playerIter.next()` and try again.
Stephen C
I apologize, I was just copying and pasting your code, and forgot to remove the parameter. I'll update for correctness.
Jack Leow
A: 

The only difference with the to snippets is the method of getting a value for p. In the first java is iterating over players, in the second you are doing it explicitly. The most likely cause of the null pointer error is p being null. If deck was null both snippets would throw a null exception. The same is true of addCard and dealCard, if either method were to throw a null pointer error both snippets would do so.

It looks like java's for-each syntax is doing a check for null before executing the body of the loop.

This question talks about the difference: http://stackoverflow.com/questions/2422690/java-for-each-vs-regular-for-are-they-equivalent

Robert Menteer