Ripasso delle Collection in Java

Il Java Collection framework include le classi che implementano le seguenti interaccie : Map, List, Queue e Set.

Durante la certificazione OCA abbiamo studiato solo la classe ArrayList, per l’OCP è richiesta la conoscenza molto più approfondita delle classi fondamentali di ogni interfaccia, in particolare, vedremmo tutte le caratteristiche, come ordinarle e come cercare elementi al loro interno.

ArrayList

Questo è un oggetto che  può contenere altri oggetti, di conseguenza, non si possono memorizzare all’interno di un ArrayList, tipi primitivi, a differenza dei comuni array che possono farlo, teniamo sempre in mente però la capacità di Autoboxing di java.

List<String> aerei = new ArrayList<>();
aerei.add("md80");
aerei.add("Airbus 320");

String[] aereiArray = new String[list.size()];
aereiArray[0] = aerei.get(0);
aereiArray[1] = aerei.get(1);

In questo semplice esempio abbiamo creato un ArrayList vuoto, abbiamo inserito due oggetti stringhe e abbiamo creato un array classico utilizzando alcuni metodi che List ci mette a disposizione, come size()get(i)

Noi abbiamo creato un array classico partendo da un ArrayList, in Java possiamo anche fare il contrario, vediamo come è semplice creare una List partendo da un array

String[] aereiArray = {"md80","Airbus 321","Cessna" };
List<String> list = Arrays.asList(aereiArray); // [md80,Airbus 321]
list.set(1,"Boeing747"); // [md80,Boeing747]
aereiArray[0] = "piper"; // [piper, Boeing747]
list.remove(1); //UnsupportedOperationException

Abbiamo convertito il nostro array in un List tramite la classe Arrays, notiamo che ogni cambiamento fatto all’array si riflette anche nel nostro arrayList, questo perchè l’arrayList creato è detto a fixed-size, ovvero, mantiene un collegamento diretto con l’array classico di partenza, di fatto, non è possibile cambiarne la dimensione, vediamo come l’ultima istruzione remove genera un errore a runtime.

Ricerca e ordinamento

Questo è un argomento un pò delicato, vediamo di ripassarlo un attimo:

int[] numeri = {6,9,1,8};
Arrays.sort(numeri); // 1,6,8,9
System.out.println(Arrays.binarySearch(numeri, 6)); // 1
System.out.println(Arrays.binarySearch(numeri, 3)); // -2

La prima istruzione System.out stampa 1 poichè l’elemento cercato si trova alla posizione 1 del nostro array ordinato, ma la seconda da un numero strano, -2 … questo perchè java ci dice che l’elemento è mancante, poichè ci restituisce un indice minore di 0, inoltre, ci da anche un informazione su dove dovrebbe trovarsi se ci fosse, e lo fa sottraendo 1 all’ipotetica posizione, nel nostro caso, il valore 3 dovrebbe trovarsi dopo 1, quindi a posizione 1, java sottrae 1 e nega il risultato … ecco il -2, vediamo ancora un altro esempio :

List<Integer> lista = Arrays.asList(9,7,5,3);
Collections.sort(lista);
System.out.println(Collections.binarySearch(list,3)); // 0
System.out.println(Collections.binarySearch(list,2)); // -1

Perchè -1 ? rifacciamo i calcoli, 2 non è presente, quindi il risultato sarà negativo, però dovrebbe trovarsi come primo elemento del nostro array, quindi in posizione 0, java sottrae 1 .. quindi -1

Notiamo che qui abbiamo utilizzato binarySearch di Collections invece che di Arrays, in Java 8 questo è possibile poichè l’interfaccia Collections ha un metodo statico binarySearch

Classi Wrapper e autoboxing

Facciamo un semplice ripasso sulla funzionalità di autoboxing che converte automaticamente i primitivi al corrispondete oggetto Wrapper.

L’unica cosa su cui dobbiamo stare attenti è quando utilizziamo una Collection con l’autoboxing, per via della precedenza che Java da, vediamo questo esempio :

List<Integer> numeri = new ArrayList<>();
numeri.add(1);
numeri.add(new Integer(3));
numeri.add(new Integer(5));
numeri.remove(1);
numeri.remove(new Integer(5));
System.out.println(numeri);

Potremmo essere sorpresi dal fatto che questo array stamperà : [1]

Abbiamo aggiunto 3 valori con le istruzioni add portando la nostra lista a contenere [1,3,5], poi abbiamo invocato remove(1), potremmo essere portati a voler rimuovere l’oggetto Integer con valore 1, ma il metodo remove è overloadato, e uno di questi prende come parametro l’INDICE da rimuovere di tipo int primitivo, avendo noi passato 1 literal che è un int primitivo, java invocherà questo metodo che rimuove l’elemento a posizione 1, il nostra array vale ora [1,5] poichè a posizione 1 c’è l’Integer 3.

Ora invochiamo remove(new Integer(5)) che invoca il metodo remove (Object) che di fatto rimuovere l’oggetto integer uguale a 5, rendendo il nostro array [1]