I can't figure out why ArrayIndexOutOfBoundsException is thrown here

I'm trying to make a small program that creates a deck of cards. All of the code compiles, but when I try to run the tester class, it says:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 52
at cardDeck.giveValue(cardDeck.java:23)
at CardTest.main(CardTest.java:6)

I've only been using java for a few weeks, so I don't know exactly where the problem is, or how to fix it. I'd appreciate any help.
Card class:

public class Card {
 private int value;
 private String name;
 private String suit;

 public void setValue(int v){
  value = v;
 }
 public int getValue(){
  return value;
 }

 public void setName(String n){
  name = n;
 }
 public String getName(){
  return name;
 }

 public void setSuit(String s){
  suit = s;
 }
 public String getSuit(){
  return suit;
 }

}

Card Deck class:

public class cardDeck {

 int [] values = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
 String[] names = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "King", "Queen", "Jack", "Ace"};
 String[] suits = {"Clubs", "Spades", "Hearts", "Diamonds"};

 public Card[] giveName (Card[] d){
 int j = 0;
 while(j < 52){
  for(String k: names){
   d[j] = new Card();
   d[j].setName(k);
    j++;
   }
  }
  return d;
 }

 public Card[] giveValue(Card[] e){
  int a = 0;
  while(a < 52){
   for(int m: values){
     if((e[a].getName().equals("King")) || (e[a].getName().equals("Ten")) || (e[a].getName().equals("Queen")) || (e[a].getName().equals("Jack"))){
      e[a].setValue(10);
      a++;
     }else if(e[a].getName().equals("Ace")){
      e[a].setValue(11);
      a++;
     }else{
      e[a].setValue(m);
      a++;
     }
    }
   }
   return e;
  }

 public Card[] giveSuit(Card[] f){
  int b = 0;
  while(b < 52){
   for(String l:suits){
    f[b].setSuit(l);
    b++;
    }
   }
   return f;
 } 
}

Tester class:

class CardTest {
 public static void main(String[] args){
  Card[] deck = new Card[52];
  cardDeck playingCards = new cardDeck();
  playingCards.giveName(deck);
  playingCards.giveValue(deck);
  playingCards.giveSuit(deck);




  for(int q = 0; q < 52; q++){
   System.out.println("A "+deck[q].getName()+ " of " +deck[q].getSuit()+ " " +deck[q].getValue());
  }
 }
} 
Jon Skeet
people
quotationmark

Look at your nested loop:

while(a < 52) {
  for(int m: values) {
    // Various things which increment a
  }
}

You're incrementing a lots of times for each iteration of the while loop... which means you'll easily end up with a being 52 during the loop, at which point you'll get an exception. You've got the same problem in other methods too, such as giveSuit and giveName. The other methods just about work because your other arrays have lengths which divide exactly into 52 - whereas values has only 10 elements, so after 5 iterations of the while loop you'll be on a = 50... so after 3 more iterations of the nested loop, you'll blow up. But why do you have nested loops at all?

While it would be possible to fix your existing giveValue method, it would be much simpler to rewrite it as:

public Card[] giveValue(Card[] e) {
  for (int i = 0; i < 52; i++) {
    int rawValue = (i % 13) + 2; // Value 2-14
    if (rawValue == 14) {
      e[i].setValue(11); // The ace
    } else if (rawValue >= 11 && rawValue <= 13) {
      e[i].setValue(10); // Jack to King
    } else {
      e[i].setValue(rawValue);
    }
  }
  return e;
}

I would actually suggest a redesign - I suggest you make your Card class immutable. Think of real life - a card never changes after it's been created, so why should one of your Card objects? Just pass the value/suit/name into the constructor, and store them in final fields.

(Additionally, I suggest you fix the name of your cardDeck class to follow Java naming conventions, and when you have fields which aren't logically part of the state of a particular instance - such as your values, suits and names fields - you make them static.)

people

See more on this question at Stackoverflow