0

In the following(wrong) code I want to inizialize the objects contained in the array cards to create a deck. Is there a way to do it through an enhanced for loop or have I to use the "standard" for loop?

cards = new Card[SUITS][RANKS];

for(Card[] suit : cards) {
    for(Card card : suit) {
        card = new Card(suitVar, rankVar);
    }
}
Marco Fazio
  • 61
  • 2
  • 6
  • 3
    Do you know the difference between [`call by value` and `call by reference`](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value)? – Tom Feb 19 '15 at 19:30

3 Answers3

2

No, this is not possible, because an enhanced for loop will give a reference to the current element. Assigning a new object to the reference won't assign the element to the array. There is no substitute for using an array access expression to assign an element to an array.

You can use two "traditional" for loops with an array access expression to initialize the array.

for (int s = 0; s < SUITS; s++)
   for (int c = 0; c < RANKS; c++)
       cards[s][c] = new Card(...);

It's possible to use an array initializer, but it would tedious, excessively verbose, and error-prone.

cards = new Card[][] {
  {new Card(...), new Card(...), ... },
  {new Card(...), new Card(...), ... },
  ...};

Interestingly, because the 2D array is implemented as an array of arrays, and array references are used, the outer array can be initialized with an enhanced for loop, as long as the inner array is initialized with a "traditional" loop. This works because suit is an array in cards, so suit[c] is an element in cards.

cards = new Card[SUITS][RANKS];

for(Card[] suit : cards) {
    for(int c = 0; c < RANKS; c++) {
        suit[c] = new Card(suitVar, rankVar);
    }
}
rgettman
  • 176,041
  • 30
  • 275
  • 357
0

No, you can't use foreach.
This is mainly because for each is read only, but also because you would overwrite the reference of the object in the loop. Java doesn't work this way. Well, I don't know one object oriented language, where this would work.

You could test it with this simple example:

String[] strings = new String[10];
for(String s: strings)
    s = "This won't work!";

for (String s : strings)
    System.out.println(s);

It would print out

null
null
null
null
null
null
null
null
null
null

The normal way to go is to use a normal for-loop.

Zhedar
  • 3,480
  • 1
  • 21
  • 44
0

For this particular example, a good strategy would be to create enums for suits and ranks. Then you can initialize a deck by looping over those.

public enum Suit { CLUB, DIAMOND, HEART, SPADE }
public enum Rank {
    ACE,
    TWO,
    ...
    QUEEN,
    KING
}

Then

List<Card> deck = new ArrayList(Suit.values().length * Rank.values.length);
for (Suit s: Suit.values()) {
    for (Rank r: Rank.values()) {
        deck.add(new Card(s, r));
    }
}

This allows you to use enhanced for loops over the enums, rather than the array of cards itself. It's also a better representation of the system you're trying to model. As such, it's heavily dependent on the specific case, but this can be applied to more than just cards with a suit and rank. Whether this is appropriate should be determined on a case by case basis.

So to answer more directly: not the way you're doing it, but with an alternative (and in this case, better) model, it becomes possible.

jpmc26
  • 28,463
  • 14
  • 94
  • 146