#howtodev - Introduzione ai vettori in java
PRECEDENTE: Guida Java Parte 2 - Blocchi di codice←
SUCCESSIVO: Guida Java Parte 4 - Metodi←
Java è stato per anni uno dei linguaggi più utilizzati, da poco sorpassato da Python in fama, ma ancora oggi è fondamentale per tantissime aziende che lavorano nel mondo IT.
Obiettivi
In questo articolo saranno trattati:
- I vettori o array di tipi primitivi
- La scomposizione di una stringa in tutti i suoi caratteri
Prerequisiti
I prerequisiti richiesti da questo articolo sono stati affrontati nei due precedenti articoli:
- Introduzione alla programmazione in java : variabili, main e operazioni tra tipi di base
- Introduzione ai vari blocchi di codice in Java : If, switch, for, while e do-while in java
Accumulare più dati dello stesso tipo: i vettori
A volte è necessario, nonché comodo, che tanti dati simili tra di loro siano agglomerati in un unico luogo dove poterli operare insieme, pensando ad una serie di casi d’uso tra cui:
- Una serie di voti scolastici di cui poi farne una media
- Coppie di numeri che indicano coordinate di un punto
- Una serie di “booleani” che potrebbero indicare dei check “vero-falso” di una tabella o un quiz.
Nei linguaggi di programmazione questo concetto è detto “vettore” o “array”.
Creazione di un vettore
Vediamo come creare un vettore in java, genericamente:
tipo [] nomevariabile = new tipo [dimensione];
Più nel dettaglio, creiamo un vettore di 10 interi:
int [] voti = new int [10];
Possiamo peraltro crearlo direttamente con degli elementi al suo interno, senza specificare la dimensione, così:
tipo [] nomevariabile= {
elemento1,elemento2,elemento3
};
Esempio concreto con degli interi:
int [] voti={
1,2,3,10,-1
};
Attenzione: la sintassi di creazione “diretta” usando gli elementi è possibile solo alla prima creazione, in fase di nuovo assegnamento non è più possibile.
Praticamente parlando:int[]voti={1,2,3,4};va bene.voti={3,4,5,6};scritto successivamente no.
Normalmente tutti gli elementi di un vettore vengono creati con i così detti “valori di default”, se non specificati con la sintassi diretta. Questo significa che :
- i numeri son tutti a
0 - i booleani a
false - i caratteri son tutti uguali al carattere
vuoto - Stringhe ed oggetti complessi sono
null, ovvero come se non esistessero.
Quando si utilizza un vettore, la prima cosa da fare quindi è pensare a cosa devono essere assegnati i singoli elementi.
Richiamare i vettori all’interno di un vettore
E come richiamare un valore di un vettore? Anche qui nulla di complesso, supponendo di voler richiamare l’elemento “n”, lo si può richiamare scrivendo:
nomevettore[n-1]
Nota:
gli indici dei vettori partono da
0, quindi il vettoreint [] voti {3,2,5};ha si tre celle, ma la prima ha indice0, la seconda indice1e la terza indice2. Riferendoci all’esempio quindi:
voti[0] = 3voti[1] = 2voti[2] = 5
Avendo il numero della cella (o indice) possiamo operare per l’appunto su quel singolo valore:
- assegnargli un valore :
nomevettore[indice]=valore; - stamparlo o usarlo in un calcolo :
System.out.println(nomevettore[indice]);
Possiamo sempre sapere quante celle ha un vettore (numero massimo degli elementi) usando la parolina magica length:
nomevettore.length. L’ultimo elemento avrà indice nomevettore.length-1
Uso dei vettori
In generale i vettori si operano a partire dai loro elementi, per stampare ad esempio i valori di un vettore, dovrete prendere ad uno ad uno le celle e stamparle.
Detta così sembra complicato ed inutile, immaginatevi vettori di 100 elementi operati singolarmente uno ad uno, cosa ci porterebbe ad usare un vettore e non tante variabili separate?
In realtà usando i loop le operazioni su un vettore risultano molto semplici! Vediamo un esempio concreto. Supponiamo di avere 5 voti, e volerne fare la media. Senza vettori sarebbe:
public class SenzaVettore{
public static void main(String...args){
int voto1=7, voto2=5,voto3=9,voto4=6,voto5=10;
int media=voto1+voto2+voto3+voto4+voto5;
media=media/5;
System.out.println(media);
}
}
Ora vediamo come sarebbe lo stesso codice ma con i vettori:
public class vettore{
public static void main(String...args){
int[] voti = {7,5,9,6,10};
int media=0;
for(int i=0;i<voti.length;i++) media+=voti[i];
media=media/voti.length;
System.out.println(media);
}
}
Ad un primo occhio: abbiamo scritto addirittura un istruzione in più! Ma osserviamo alcuni vantaggi:
- non abbiamo dovuto creare 5 variabili per i voti, ma una sola che le rappresenta tutte e 5, che è più facile da richiamare
- il codice non dipende più dal numero di voti: se un giorno i voti diventassero 10, ci sarebbe solo da aumentare i numeri nel vettore, il resto verrebbe tutto aggiornato di conseguenza
- se ci fosse più di un operazione per ogni singolo elemento da fare, il numero di istruzioni aumenterebbe in proporzione: due istruzioni per variabile raddoppierebbero; con la gestione del
forinvece, ogni istruzione viene applicata a tutte le variabili.
Un esempio più chiaro
Se non siete ancora convinti, vediamo un esempio più complesso: avendo una serie di 10 caratteri, vogliamo trasformare le maiuscole in minuscole e le minuscole in maiuscole, stampare tutte le variabili e mandare solo all’ultima variabile a capo.
Già solo il pensiero di inizializzare 10 variabili char personalmente mi fa venire l’angoscia, senza scriverlo dunque tutto, ecco come apparirebbe un programma senza i vettori nelle sue prime righe:
public class SenzaVettore{
public static void main (String [] args) {
//inizializziamo le variabili
char c1='c',
c2='I',
c3='a',
c4='O',
c5=' ',
c6='A',
c7=' ',
c8='v',
c9='O',
c10='i';
//controlliamo una per una
//che sia una lettera e che sia minuscola o maiuscola
if (c1>='a'&&c1<='z'){
// c1 è minuscola, va trasformata in maiuscola
c1=(char)(c1-'a'+'A');
} else if(c1>='A' && c1<='Z'){
//c1 è maiuscola, va trasformata in minuscola
c1=(char)(c1+'a'-'A');
}
// se non è ne una lettera minuscola ne maiuscola non faremo nulla
//controlliamo ora c2..
if (c2>='a'&&c2<='z'){
// c2 è minuscola, va trasformata in maiuscola
c2=(char)(c2-'a'+'A');
} else if(c2>='A' && c2<='Z'){
//c1 è maiuscola, va trasformata in minuscola
c2=(char)(c2+'a'-'A');
}
// e cosi via per altre 8 volte...
System.out.println(""+c1+c2+c3+c4+c5+c6+c7+c8+c9+c10);
}
}
Inizia a diventare un po’ più difficile da leggere vero? Vediamo ora lo stesso programma, con i vettori:
public class ConVettore{
public static void main (String [] args) {
char [] c= {
'c','I','a','O',
' ','A',' ',
'v','O','i'
};
//controlliamo una per una
//che sia una lettera e che sia minuscola o maiuscola
for (int i=0; i<c.length;i++){
if(c[i]>='a'&&c[i]<='z')
c[i]=(char)(c[i]-'a'+'A');
else if ( c[i]>='A'&&c[i]<='Z')
c[i]=(char)(c[i]-'A'+'a');
System.out.print(c[i]);
}
System.out.println();
}
}
- più corto
- più semplice da modificare
- più semplice da leggere
Problemi con i vettori : cosa non bisogna fare
I problemi più comuni con i vettori son sicuramente i così detti IndexOutOfBound: ovvero quando, per difetto o per eccesso che sia, si esce al di fuori delle celle riservate.
Replichiamo uno dei casi che sicuramente si verifica di più :
int [] voti = new voti[5];
voti[5]=3;
voti[5] non esiste. Come già detto in precedenza, gli indici dei vettori partono da 0, quindi variano da 0 al numero di elementi meno 1. voti[5] esce fuori dal range, poiché l’ultimo elemento è voti[4]
Analogamente non esiste, per ovvi motivi, voti[-1]. Difficilmente in programmazione si utilizzano gli indici espliciti comunque, in genere si utilizzano all’interno di un ciclo di for, vediamo in questo caso come si potrebbe sbagliare:
for (int i=0; i<=vettore.length; i++)
Questo è sbagliato poichè gli indici come già detto prima dovrebbero arrivare a vettore.length-1, motivo per cui all’interno di un for si utilizza il < non <=
Scorrere i vettori al contrario, come non farlo e come farlo
Un altro caso tipico, scorriamo un vettore ma al contrario (dall’ultima cella fino alla prima):
for (int i=vettore.length; i>0; i++)
Questo è sbagliato per diversi motivi:
- se
iparte davettore.lengthsi ricade negli errori di cui sopra - Al contrario del caso precedente, scorrendo un vettore al contrario ci sarà sempre l’uguaglianza nella comparazione, poiché l’ultima cella da visitare sarà proprio
0. idovrà decrementare, non incrementare
La forma giusta sarebbe stata:
for (int i=vettore.length-1; i>=0; i--)
Le stringhe sono un vettore di caratteri ?
La risposta è si.
In alcuni linguaggi questo è esplicito mentre in Java è tutto nascosto dietro al tipo “Stringa”, che consente poi di operare su una serie di operazioni, tuttavia questo introduce delle complicazioni a coloro che ancora non sanno cos’è un oggetto.
Innanzitutto le Stringhe sono vettori immutabili, non potete modificarne i singoli caratteri, ogni aggiunta o modifica ad una stringa porterà ad una nuova istanza. Ho purtroppo visto professionisti fare errori gravi non sapendo questa cosa.
Essendo immutabile, una stringa può solo essere letta, e questo accade tramite la parolina magica charAt seguita dall’indice del carattere tra parentesi tonde. Vediamo come usarla:
String alfa="Ciao a tutti";
System.out.println(alfa.charAt(2)); // stamperà a
Per sapere la lunghezza useremo sempre la parolina “length” ma seguita da due parentesi tonde: ()
Riprendiamo l’esempio delle maiuscole e vediamo come affrontarlo usando però la Stringa come un vettore:
public class ConStringa{
public static void main (String [] args) {
String frase="cIaO A vOi";
for (int i=0; i<frase.length();i++){
System.out.print(
(frase.charAt(i)>='a'&&frase.charAt(i)<='z') ? // if ternario
(char)(frase.charAt(i)-'a'+'A') :
(frase.charAt(i)>='A'&&frase.charAt(i)<='Z') ? //elseif ternario
(char)(frase.charAt(i)-'A'+'a') :
frase.charAt(i) // else
); // qui finisce System.out.print
}
System.out.println();
}
}