I'm only assigning one value to my final variable but still I'm getting an error

I'm getting an error when making my instance Strings cardRank and cardSuit final and I think that I'm only assigning them values once in my code. I've commented which ones I'm talking about in my code.

import java.util.Arrays;

public class Card{

protected static final String[] SUITS = {"spades", "clubs", "hearts", "diamonds"};
protected static final String[] RANKS = {"1","2","3","4","5","6","7","8","9","10","J","Q","K"};

private String cardRank; // I want to make this final
private String cardSuit; // I want to make this final

public Card(){
    this(RANKS[(int) (Math.random() * RANKS.length)] , SUITS[(int) (Math.random() * SUITS.length)]);
}

public Card(String cardRank, String cardSuit){
    setRank(cardRank);
    setSuit(cardSuit);
}

private boolean isValidRank(String cardRank){
    cardRank = cardRank.toUpperCase();
    return Arrays.asList(RANKS).contains(cardRank);
}

private boolean isValidSuit(String cardSuit){
    cardSuit = cardSuit.toLowerCase();
    return Arrays.asList(SUITS).contains(cardSuit);
}

private void setRank(String cardRank){
    if(isValidRank(cardRank)) this.cardRank = cardRank;
    else this.cardRank = "Invalid Suit";
}

private void setSuit(String cardSuit){
    if(isValidSuit(cardSuit)) this.cardSuit = cardSuit;
    else this.cardSuit = "Invalid Suit";
}

public String getRank(){
    return cardRank;
}

public String getSuit(){
    return cardSuit;
}

public void printCard(){      
    System.out.println(getSuit() + " " + getRank());
}

}

Jon Skeet
people
quotationmark

You can only assign to a final field within a constructor body (or as part of the declaration, or an instance initializer). So basically, you should ditch your setSuit and setRank methods.

public Card(String cardRank, String cardSuit) {
    this.cardRank = isValidCardRank(cardRank) ? "Invalid rank";
    this.cardSuit = isValidCardSuit(cardSuit) ? "Invalid suit";
}

Or better:

public Card(String cardRank, String cardSuit) {
    this.cardRank = validateRank(cardRank);
    this.cardSuit = validateSuit(cardSuit);
}

where the validate* methods would throw IllegalArgumentException if the valid is invalid.

Or better yet, make Suit and Rank enums, so the only values are valid ones, and you just need to check for nullity...

people

See more on this question at Stackoverflow