Insiemi finiti di valori

Può capitare che un programma debba rappresentare e gestire insiemi ristretti di possibili valori, ad esempio;
  • i semi di un mazzo di carte (cuori, quadri, fiori, picche),

  • il sesso di una persona (M, F),

  • i giorni della settimana (lunedì, ..., domenica),

  • le sigle di stati o di provincie,

  • lo stato civile di una persona,

  • diversi tipi di moneta, ecc.

In questi casi vorremmo usare delle variabili che possono assumere solo un limitato numero di valori.




Soluzioni ad hoc

Vediamo alcune soluzioni piuttosto diffuse:
  • usare delle stringhe per rappresentare i valori possibili: nell'esempio dei semi avremmo dunque "cuori", "quadri", "fiori" e "picche".

    Però in questo modo il tipo di una variabile seme sarebbe comunque String e quindi poco indicativo per l'analisi del programma:

    1. nulla impedirebbe di assegnare valori non previsti alla variabile seme, come le stringhe "ori" o "bastoni",
    2. l'ordine naturale degli elementi sarebbe quello lessicografico, che non necessariamente coincide con quello voluto.
    3. manca la possibilità di associare anche dei valori agli elementi del dominio (esempio dei tipi di moneta).

  • Definire nuove costanti ad hoc il cui nome richiama l'elemento (in maniera mnemonica) e il cui valore permette di confrontare elementi diversi (es. per ordinarli). Ad esempio potremmo definire quattro costanti intere CUORI=1, QUADRI=2, FIORI=3 e PICCHE=4:
    1. adesso possiamo scegliere noi i valori
    2. rimane il problema che il tipo di queste costanti non è indicativo del dominio cui appartengono
    3. inoltre i valori assegnati potrebbero essere completamente arbitrari (artificiosità) e l'aggiunta di nuovi elementi potrebbe comportare il riassegnamento dei valori alle costanti preesistenti (scarsa scalabilità e modularità).

  • Altre soluzioni (che non stiamo a illustrare perché richiedono alcune nozioni più sofisticate) sono possibili, ma presentano sempre lo svantaggio di costringere il programmatore a inventare un meccanismo ad hoc per il particolare dominio applicativo.




Tipi enumerativi

Alcuni linguaggi di programmazione permettono di definire nuovi tipi semplicemente elencando tutti gli elementi possibili che hanno quel tipo (i valori del dominio corrispondente).

Dalla versione 5.0 anche Java comprende i cosiddetti tipi enumerativi, che possono essere dichiarati con la parola chiave enum e poi usati per dichiarare variabili di quel tipo: Una variabile di tipo enumerativo potrà assumere soltanto quei valori elencati nel definire il tipo enumerativo.

La soluzione adottata da Java è assai più flessibile e potente di quella presente in altri linguaggi (es. C, C++, pascal), perché è integrata perfettamente con i principi della programmazione a oggetti e con alcuni costrutti di programmazione.




Dichiarazioni di tipi enumerativi

Per definire un tipo enumerativo è sufficiente usare la parola chiave enum e elencare i possibili valori di quel tipo.

Esempi di dichiarazioni di nuovi tipi:
 
enum Seme { CUORI, QUADRI, FIORI, PICCHE }

enum Giorno { LUNEDI, MARTEDI, MERCOLEDI, GIOVEDI,
              VENERDI, SABATO, DOMENICA }

enum Mese { GENNAIO, FEBBRAIO, MARZO, APRILE, MAGGIO, GIUGNO, 
            LUGLIO, AGOSTO, SETTEMBRE, OTTOBRE, NOVEMBRE, DICEMBRE }

In generale la sintassi è la seguente:
 
 
public class <MiaClasse> {
 
    enum <NuovoTipoEnum> { <valore1>, ..., <valoreN> }
 
    ...
 }

I tipi enumerativi prevengono assegnamenti errati di valori non previsti.
 
String tuaCarta = "SPADE"; // Compila
Seme miaCarta = Seme.SPADE; // Errore di compilazione!
 
Giorno oggi = Giorno.MERCLDI; // Errore di compilazione!




Variabili di tipo enumerativo

Una volta definito un nuovo tipo enumerativo è possibile dichiarare variabili di quel tipo.

Esempi di assegnamenti a variabili di tipo enumerativo:
 
Seme miaCarta;
miaCarta = Seme.CUORI;

Giorno oggi = Giorno.MERCOLEDI;

Mese inizioAA = Mese.SETTEMBRE;

In generale la sintassi è la seguente:
 
 
<TipoEnum> <variabile> = <TipoEnum>.valore;

Oltre ai valori elencati nella definizione del tipo enumerativo, le variabili di un tipo enumerativo possono sempre assumere anche un altro valore: null.




Confronto tra valori di tipo enumerativo

I valori di tipi enumerativi possono anche essere confrontati tra loro. Per il confronto di uguaglianza si può usare == o equals indifferentemente (i valori enumerati sono in realtà oggetti, ma sono oggetti unici).

Per il confronto di ordinamento bisogna usare compareTo, analogamente a quanto visto per il confronto tra stringhe.
 
 
public class ProvaCarte {
 
    enum Seme { CUORI, QUADRI, FIORI, PICCHE }
 
    public static void main (String[] args) {
 
        Seme miaCarta, tuaCarta, suaCarta;
        miaCarta = Seme.CUORI;
        tuaCarta = Seme.FIORI;
        suaCarta = Seme.CUORI;
 
        System.out.println(miaCarta==tuaCarta); // false
        System.out.println(miaCarta.equals(tuaCarta)); // false
 
        System.out.println(miaCarta==suaCarta); // true
        System.out.println(miaCarta.equals(suaCarta)); // true
 
        System.out.println(miaCarta==Seme.CUORI); // true
        System.out.println(miaCarta.equals(Seme.CUORI)); // true
 
        System.out.println(miaCarta.compareTo(tuaCarta)); // -2
        System.out.println(miaCarta.compareTo(suaCarta)); // 0
        System.out.println(tuaCarta.compareTo(miaCarta)); // 2
    }
}