Menu


Trascrizione diapositive

1. Librerie di utilità

  • Complessità: BASSA.


2. Che cos’è java.util e come è fatto il suo framework

  • «java.util» è un package che si può importare ed utilizzare all’interno di un programma scritto in Java, esso contiene diverse utility che permettono di farci scrivere meno codice sorgente.
  • Un componente fondamentale di «java.util» è il framework «Collections», di seguito un’immagine esemplificativa che ci consente di comprendere meglio come è fatto:
  • [Immagine] java.util

  • Apprendiamo dall’illustrazione mostrata che esistono due interfacce principali su cui si basa tutto il framework, trattasi dell’interfaccia «Collection» e dell’interfaccia «Map».
    L’interfaccia «Collection» è a sua volta estesa nelle interfacce «Set», «List» e «Queue»; «Set» è esteso in «SortedSet», che viene esteso a sua volta su «NavigableSet».
    Mentre l’interfaccia «Map» è estesa nell’interfaccia «SortedMap», che è a sua volta estesa in «NavigableMap».


3. Meccanismo del framework «Collections»

  • Il framework illustrato in precedenza permette tramite nove interfacce preimpostate di gestire diverse tipologie di elementi.
  • È necessario precisare che «java.util» non consente alcuna implementazione diretta dell’interfaccia «Collection», ma permette di utilizzare qualsiasi sua sotto-interfaccia; mentre l’interfaccia «Map» a differenza di «Collection» può essere implementata direttamente.
  • Di seguito un accenno pratico che riguarda il meccanismo delle interfacce implementabili:

Interfaccia

Funzionamento

Set

Permette di aggiungere qualsiasi tipo di elemento ma non ammette duplicati; le sotto-interfacce «SortedSet» e «NavigableSet» aggiungono nuove funzionalità come la possibilità di ordinare la lista.

List

Associa ad ogni elemento aggiunto un indice incrementale di riferimento, che equivale alla posizione dell’elemento nella lista stessa.

Queue

Definisce nuovi metodi per l’utilizzo dei dati.

Map

Associa ad ogni elemento aggiunto una chiave univoca, il che significa che ad ogni chiave può essere associato un solo elemento; anche in questo caso le sotto-interfacce «SortedMap» e «NavigableMap» aggiungono nuove funzionalità come l’opportunità di sfogliare la lista.



4. Implementazione di Set

  • Sappiamo che «Set» permette di aggiungere qualsiasi tipo di elemento ma non ammette duplicati; per utilizzare «Set» bisogna creare un oggetto di tipo «HashSet». Ecco un esempio:

[Download]

public class Programma {
public static void main(String[] args) {
HashSet set = new HashSet(); // Crea un oggetto di tipo HashSet
set.add("Giovanni"); // Aggiunge elemento Giovanni
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Giacomo"); // Aggiunge elemento Giacomo
System.out.println(set); // Mostra su schermo la lista
}
}

  • Ed ecco l’output del codice sorgente:

  • Giovanni, Giacomo, Luigi

  • Notiamo che l’elemento «Luigi» è stato aggiunto soltanto una volta.


5. Implementazione di SortedSet

  • L’implementazione ordinaria di «SortedSet» è data dalla generazione di un oggetto di tipo «TreeSet», che a differenza di «HashSet», ordina gli elementi in modo crescente.
  • Un esempio di «SortedSet» è dato dal seguente codice:

[Download]

public class Programma {
public static void main(String[] args) {
TreeSet set = new TreeSet(); // Crea un oggetto di tipo TreeSet
set.add("Giovanni"); // Aggiunge elemento Giovanni
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Giacomo"); // Aggiunge elemento Giacomo
System.out.println(set); // Mostra in ordine crescente
}
}

  • Dall’output si evince che gli elementi sono visualizzati in modo crescente (poiché si tratta di stringhe, esse sono ordinate alfabeticamente):

  • Giacomo, Giovanni, Luigi


6. Altre operazioni possibili con SortedSet

  • Inoltre l’interfaccia «SortedSet» consente di eseguire delle particolari operazioni; ad esempio sarà possibile far restituire il primo e/o l’ultimo elemento della lista creata, oppure mostrare un preciso intervallo di elementi a seconda delle proprie esigenze:

[Download]

  • public class Programma {
    public static void main(String[] args) {
    TreeSet set = new TreeSet();
    /* Aggiunta manuale di elementi in ordine crescente (in modo che compaiano posizionati nella lista così come li vediamo) */
    set.add("Alessandro"); set.add("Filippo"); set.add("Giacomo"); set.add("Giovanni"); set.add("Giuseppe"); set.add("Luigi");
    // Primo elemento
    System.out.println(set.first()); // Verrà restituito l’elemento Alessandro
    // Ultimo elemento
    System.out.println(set.last()); // Verrà restituito l’elemento Luigi
    // Intervallo tra Filippo e Giuseppe (Giuseppe escluso)
    System.out.println(set.subSet("Filippo", "Giuseppe")); // Verrà restituito Filippo, Giacomo, Giovanni
    // Elementi minori di Giacomo(escluso)
    System.out.println (set.headSet("Giacomo")); // Verrà restituito Alessandro, Filippo
    // Elementi maggiori di Giacomo(incluso)
    System.out.println (set.tailSet("Giacomo")); // Verrà restituito Giacomo, Giovanni, Giuseppe, Luigi
    }
    }


7. Implementazione di NavigableSet

  • «NavigableSet» estende «SortedSet»; Per implementarlo è necessario creare comunque un oggetto di tipo «TreeSet».
  • In aggiunta alle funzioni di «SortedSet», i metodi di «NavigableSet» consentono di ordinare la lista restituita anche in ordine decrescente; inoltre consentono in base ad un elemento passato in argomento, la restituzione dell’elemento minore, minore uguale, maggiore o maggiore uguale.
  • I metodi «subSet», «headSet» e «tailSet», esistono anche in «NavigableSet», ma accettano parametri aggiuntivi che permettono di personalizzare i limiti degli intervalli restituiti.
  • Infine i metodi «poolFirst» e «poolLast» permettono rispettivamente di restituire e rimuovere il primo e l’ultimo elemento della lista, se è disponibile, altrimenti verrà restituito valore «null».
  • Nelle prossime diapositive verranno illustrate nel dettaglio tutte le novità.


8. Implementazione di NavigableSet

  • Mostriamo adesso per mezzo di un dimostrazione pratica, la possibilità di ordinare gli elementi secondo un ordine di tipo decrescente, rispetto all’ordine crescente stabilito automaticamente all’atto della creazione della lista.
  • Un esempio di ordinamento decrescente è dato dal seguente codice:

[Download]

public class Programma {
public static void main(String[] args) {
TreeSet set = new TreeSet(); // Crea un oggetto di tipo TreeSet
set.add("Giovanni"); // Aggiunge elemento Giovanni
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Luigi"); // Aggiunge elemento Luigi
set.add("Giacomo"); // Aggiunge elemento Giacomo
System.out.println(set); // Mostra in ordine crescente
System.out.println(set.descendingSet()); // Mostra in ordine decrescente
}
}

  • Dall’output si evince che gli elementi sono visualizzati in modo crescente nel primo rigo e decrescente nel secondo:

  • Giacomo, Giovanni, Luigi
  • Luigi, Giovanni, Giacomo


9. Implementazione di NavigableSet

  • «NavigableSet» è conosciuto per alcune funzioni che permettono di navigare tra gli elementi di una lista; sarà quindi possibile mostrare l’elemento minore, minore uguale, maggiore o maggiore uguale rispetto ad un preciso argomento passato come parametro:

[Download]

  • public class Programma {
    public static void main(String[] args) {
    TreeSet set = new TreeSet();
    // Aggiunta manuale di elementi in ordine crescente (in modo che compaiano posizionati nella lista così come li vediamo)
    set.add(1); set.add(2); set.add(3); set.add(4); set.add(5);
    // Elemento precedente
    System.out.println(set.lower(3)); // Verrà restituito il numero 2
    // Elemento precedente o uguale
    System.out.println(set.floor(3)); // Verrà restituito il numero 3
    // Elemento precedente o uguale
    System.out.println(set.floor(8)); // Verrà restituito il numero 5
    // Elemento successivo o uguale
    System.out.println(set.ceiling(3)); // Verrà restituito il numero 3
    // Elemento successivo o uguale
    System.out.println(set.ceiling(-8)); // Verrà restituito il numero 1
    // Elemento successivo
    System.out.println(set.higher(3)); // Verrà restituito il numero 4
    }
    }


10. Altre operazioni possibili con NavigableSet


[Download]

  • public class Programma {
    public static void main(String[] args) {
    TreeSet set = new TreeSet();
    // Aggiunta manuale di elementi in ordine crescente (in modo che compaiano posizionati nella lista così come li vediamo)
    set.add("Alessandro"); set.add("Filippo"); set.add("Giacomo"); set.add("Giovanni"); set.add("Giuseppe"); set.add("Luigi");
    // Primo elemento
    System.out.println(set.pollFirst()); // Verrà restituito e eliminato l’elemento Alessandro
    // Ultimo elemento
    System.out.println(set.pollLast()); // Verrà restituito e eliminato l’elemento Luigi
    // Intervallo tra Filippo e Giuseppe (Giuseppe escluso)
    System.out.println(set.subSet("Filippo", true, "Giuseppe", false)); // Verrà restituito Filippo, Giacomo, Giovanni
    // Intervallo tra Filippo e Giuseppe (Giuseppe incluso)
    System.out.println(set.subSet("Filippo", true, "Giuseppe", true)); // Verrà restituito Filippo, Giacomo, Giovanni, Giuseppe
    // Intervallo tra Filippo e Giuseppe (Filippo escluso)
    System.out.println(set.subSet("Filippo", false, "Giuseppe", true)); // Verrà restituito Giacomo, Giovanni, Giuseppe
    // Intervallo tra Filippo e Giuseppe (Filippo e Giuseppe esclusi)
    System.out.println(set.subSet("Filippo", false, "Giuseppe", false)); // Verrà restituito Giacomo, Giovanni
    // Elementi minori di Giacomo(escluso)
    System.out.println (set.headSet("Giacomo", false)); // Verrà restituito Filippo «Alessandro eliminato da PoolFirst()»
    // Elementi minori di Giacomo(incluso)
    System.out.println (set.headSet("Giacomo", true)); // Verrà restituito Filippo, Giacomo «Alessandro eliminato da PoolFirst()»
    // Elementi maggiori di Giacomo(escluso)
    System.out.println(set.tailSet("Giacomo", false)); // Verrà restituito Giovanni, Giuseppe «Luigi eliminato da PoolLast()»
    // Elementi maggiori di Giacomo(incluso)
    System.out.println(set.tailSet("Giacomo", true)); // Verrà restituito Giacomo, Giovanni, Giuseppe «Luigi eliminato da PoolLast()»
    }
    }


11. Differenza tra List e array

  • Se intendiamo creare una lista di elementi attraverso l’interfaccia «List» è necessario sapere che; un elenco di questo genere accetta elementi duplicati, giacché ad ogni elemento inserito viene associato un indice di tipo incrementale, proprio come avveniva con gli array.
  • Occorre precisare che tuttavia ci sono delle piccole differenze tra una «List» ed un array e sono:

  • - La dimensione di un array una volta definita non può essere più alterata, mentre implementando «List» sarà possibile modificare la capacità del vettore durante l’esecuzione del software.
  • - Un array tollera anche valori di tipo primitivo, mentre con «List» gli elementi inseriti dovranno necessariamente essere di tipo non primitivo.

  • P.S. Un elemento di tipo «String» non è un tipo primitivo.


12. Implementazione di List

  • Per implementare «List» è necessario creare un oggetto di tipo «ArrayList» o «Vector».
  • La principale differenza che intercorre tra un «ArrayList» e un «Vector» è data dalle esigenze del programmatore; se s’intende sviluppare un’applicazione utilizzando i processi, sarà opportuno creare un oggetto di tipo «Vector», perché fa uso di metodi sincronizzati; mentre se si desidera sviluppare un semplice software è consigliabile fare uso di un «ArrayList».
  • Il mio consiglio è quello di fare sempre uso di «ArrayList», anche perché l’impiego dei processi in Java è assai infrequente, inoltre, negli applicativi di tipo Enterprise i processi vengono gestiti automaticamente.


13. Implementazione di List

  • La più classica implementazione di «List» è data dalla generazione di un oggetto di tipo «ArrayList», pertanto bisognerà scrivere:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(100); // Crea un oggetto di tipo ArrayList
}
}

  • in questo caso sarà costruita una lista con capacità iniziale pari a «100», questo significa che saranno messe a disposizione «100» posizioni vuote pronte ad essere riempite.


14. Implementazione di List

  • Per modificare il numero degli elementi disponibili in un oggetto di tipo «ArrayList», si deve invocare la funzione «ensureCapacity()», ad esempio:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(100); // Crea un oggetto di tipo ArrayList
list.ensureCapacity(2000); // Nuova capacità impostata a 2000 elementi
}
}

  • constatiamo che nel quarto rigo la capacità della lista è aumentata; da «100» elementi vuoti siamo giunti a «2000» elementi.

  • In un array non sarebbe stato possibile modificare la capacità una volta impostata a priori.


15. Implementazione di List

  • Invocando il metodo «size()» a partire da un oggetto di tipo «ArrayList» è possibile ottenere il numero di elementi inseriti nella lista, quindi scrivendo:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

// Aggiunta manuale di elementi
list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

// Elementi occupati nella lista creata
System.out.println(list.size()); // Verrà restituito il numero 6
}
}

  • visualizzeremo il numero «6» e non il numero «8» (che in questo caso corrisponde alla capacità massima del vettore).


16. Implementazione di List

  • Per visualizzare un elemento di una «List» si deve utilizzare il metodo «get()», che può essere integrato in una struttura di controllo di tipo iterativo, in questo modo sarà possibile scandire tutti gli elementi della lista:

[Download]

  • public class Programma {
    public static void main(String[] args) {
    ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

    // Aggiunta manuale di elementi
    list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

    // Visualizzazione degli elementi nella lista creata
    for (int indice = 0; indice < list.size(); indice++) {
    System.out.println(list.get(indice));
    }
    }
    }


17. Implementazione di List

  • Per inserire un elemento in una implementazione di «List» è opportuno usare la funzione «add()», da cui sarà anche possibile passare in argomento la posizione:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

// Aggiunta manuale di elementi
list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

// Inserimento di un elemento specificando la posizione
list.add(4, "Marco"); // L'azione sarà svolta ma non sarà mostrato alcun risultato
}
}

  • In questo caso verrà aggiunto l’elemento «Marco» in posizione «4», gli oggetti successivi a «Marco» saranno spostati di una posizione; in questo caso «Luigi» sarà in posizione «6».


18. Implementazione di List

  • Per rimuovere un elemento si deve fare uso del metodo «remove()», passando come argomento la posizione dell’elemento nella lista:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

// Aggiunta manuale di elementi
list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

// Rimozione di un elemento specificando la posizione
list.remove(4); // L'azione sarà svolta ma non sarà mostrato alcun risultato
}
}

  • Nel caso preso in esame notiamo che l’elemento «Giuseppe» sarà rimosso.


19. Implementazione di List

  • Un altro sistema per rimuovere un elemento è quello di utilizzare «remove()» passando in argomento l’oggetto da rimuovere:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

// Aggiunta manuale di elementi
list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

// Rimozione di un elemento specificando l’elemento
list.remove("Luigi"); // L'azione sarà svolta ma non sarà mostrato alcun risultato
}
}

  • In questo caso l’elemento «Luigi» sarà rimosso e verrà restituito valore «true» dalla funzione «remove()».


20. Implementazione di List

  • Per quanto riguarda il metodo «equals()» è necessaria un attenta analisi, poiché il principio di funzionamento è piuttosto complesso; trattasi di passare in argomento un oggetto di tipo lista che sarà confrontato con il contenuto dell’oggetto chiamante, se è uguale verrà restituito il valore «true», mentre se diverso verrà restituito «false», ad esempio:

[Download]

public class Programma {
public static void main(String[] args) {
ArrayList list = new ArrayList(8); // Crea un oggetto di tipo ArrayList

// Aggiunta manuale di elementi
list.add("Alessandro"); list.add("Filippo"); list.add("Giacomo"); list.add("Giovanni"); list.add("Giuseppe"); list.add("Luigi");

// Confronto tra liste
System.out.println(list.equals(list)); // Sarà restituito true
}
}

  • in questo caso verrà restituito su schermo il valore «true», giacché il contenuto della lista passata in argomento è uguale a quello della lista chiamante (sono lo stesso oggetto).


21. Implementazione di Queue

  • Il compito dell’interfaccia «Queue» è quello di aggiungere funzioni supplementari che non sono presenti negli oggetti derivati da «List», pertanto la classe «LinkedList» è la naturale implementazione di questa nuova interfaccia.
  • Un oggetto di tipo «LinkedList» supporta nuove possibilità per operare con gli elementi; tra le addizionali funzioni segnaliamo: «add()», «offer()», «element()», «peek()», «poll()», «remove()».
  • I metodi «add()» e «offer()» permettono di aggiungere un elemento alla fine della lista; se l’inserimento non va a buon fine: «add()» lancerà un'eccezione, mentre «offer()» restituirà valore «false».
  • I metodi «element()» e «peek()» permettono di restituire il primo elemento della lista; se la lista è vuota: «element()» lancerà un'eccezione, mentre «peek()» restituirà valore «null».
  • Ed infine: i metodi «remove()» e «pool()» permettono di rimuovere il primo elemento della lista; se la rimozione non va a buon fine: «remove()» lancerà un'eccezione, mentre «pool()» ritornerà valore «null».


22. Implementazione di Map

  • Per implementare una collezione di tipo «Map» bisogna istanziare un oggetto di tipo «Hashtable», che permette la definizione di una chiave univoca per ogni elemento aggiunto.
  • Inoltre «Map» accetta unicamente elementi di tipo non primitivo; per aggiungerli questa volta non useremo più il metodo «add()» ma adopereremo il metodo «put()», che ci permette di specificare l’elemento da inserire e la sua chiave univoca di riferimento, il tutto attraverso due semplici parametri forniti in argomento.
  • Chiaramente non sono ammesse chiavi duplicate e neanche elementi che puntano a «null».
  • Infine per recuperare un elemento bisogna utilizzare il metodo «get()», passando in argomento la chiave univoca relativa all’elemento da acquisire.


23. Estrazione di dati diversi dal framework«Collections»

  • Immaginiamo di avere una lista che contiene istanze diverse:

  • public class Programma {
    public static void main(String[] args) {
    ArrayList list = new ArrayList(); // Crea un oggetto di tipo ArrayList
    list.add("Luigi"); // Aggiunge alla lista un'istanza di String
    list.add(new ArrayList()); // Aggiunge alla lista un'istanza di ArrayList
    list.add(new Persona()); // Aggiunge alla lista un'istanza della classe Persona
    }
    }

  • Per recuperare un elemento, avremo bisogno di utilizzare il casting e le collezioni eterogenee, come avevamo già visto quando abbiamo trattato il polimorfismo.
  • Fare il casting ci permette, in questo caso, di forzare l’immagazzinamento di una istanza in un oggetto, la procedura è molto semplice anche se è soggetta ad errore:

  • String stringa = (String) list.get(0); // Casting di String
    ArrayList arraylist = (ArrayList) list.get(1); // Casting di ArrayList
    Persona persona = (Persona) list.get(2); // Casting di Persona


24. Estrazione di dati diversi dal framework«Collections»

  • Se abbiamo la necessità di estrarre elementi istanziati in modo ignoto, dobbiamo ricorrere anche alle collezioni eterogenee, ecco un esempio:


  • String stringa = null;
    ArrayList arraylist = null;
    Persona persona = null;

    for (Object oggetto : list.toArray()) {
    if (oggetto instanceof String) {
    stringa = (String) oggetto; // Casting di String
    }
    if (oggetto instanceof ArrayList) {
    arraylist = (ArrayList) oggetto; // Casting di ArrayList
    }
    if (oggetto instanceof Persona) {
    persona = (Persona) oggetto; // Casting di Persona
    }
    }

  • Tuttavia il codice mostrato è anch’esso soggetto ad errore, sia nella procedura di casting, sia nell’uso dell’ operatore «instanceof».


25. Uso dei «Generics»

  • Usare i «Generics» è caldamente consigliato per non sbagliare mai, poiché nel caso in cui intendiamo implementare una «Collection», siamo obbligati ad immagazzinare su di essa, solo e soltanto un determinato tipo di istanza; ecco un esempio pratico che però produce un errore in compilazione:

  • ArrayList<String> list = new ArrayList<String>(); // Crea un oggetto di tipo ArrayList usando i Generics
    list.add("Luigi"); // Aggiunge alla lista un'istanza di String compatibile
    list.add(new ArrayList()); // Aggiunge alla lista un'istanza di ArrayList non compatibile
    list.add(new Persona()); // Aggiunge alla lista un'istanza della classe Persona non compatibile

  • L’errore è causato dagli elementi della nostra «Collection» che accetta solo istanze di «String», dalla terza riga in poi, invece, si tenta di immagazzinare rispettivamente, un «ArrayList» e un’istanza della classe «Persona».
  • Se avessimo scritto in questo modo:

  • ArrayList<String> list = new ArrayList<String>(); // Crea un oggetto di tipo ArrayList usando i Generics
    list.add("Luigi"); // Aggiunge alla lista un'istanza di String compatibile
    list.add("Giacomo"); // Aggiunge alla lista un'istanza di String compatibile
    list.add("Fabio"); // Aggiunge alla lista un'istanza di String compatibile

  • Non avremmo riscontrato nessun tipo di errore, giacché ogni elemento immagazzinato è di tipo «String».


26. Perché usare i «Generics»

  • Usare i «Generics» deve considerarsi una pratica fortemente raccomandata sulla quale il lettore deve abituarsi, specialmente riguardo l’approccio mentale.
  • Come abbiamo già visto nella precedente diapositiva, i «Generics» ci permettono di evitare di incorrere in errori in fase di esecuzione, dunque, otteniamo un considerevole risparmio di risorse e tempo di debug.
  • Inoltre a partire dalla versione 5 di Java, se utilizziamo una «Collection» senza parametrizzarla tramite «Generics», il compilatore ci segnalerà un messaggio di warning.
  • Osserviamo infine che, usare il casting sulle «Collection» è da considerarsi inutile, proprio grazie all’uso dei «Generics» che accettano soltanto un determinato tipo di istanza.


27. Gestione delle date

  • Per gestire le date in Java ci serviremo di 5 librerie:

  • - Date (di java.util)
  • - Calendar (di java.util)
  • - GregorianCalendar (di java.util e sottoclasse di Calendar)
  • - SimpleDateFormat (di java.text)
  • - DateFormat (di java.text)

  • Le prime tre librerie ci serviranno a creare un oggetto che contiene una data, mentre le ultime due ci serviranno a formattare la data secondo un particolare formato.


28. Gestione delle date

  • In questo primo esempio stampiamo a schermo la data e l’ora corrente, sfruttando la classe «GregorianCalendar» (di java.util e sottoclasse di «Calendar»):

  • GregorianCalendar data = new GregorianCalendar(); // Dichiarazione e istanza di GregorianCalendar

    int giorno = data.get(Calendar.DATE); // Imposta il giorno corrente
    int mese = data.get(Calendar.MONTH) + 1; // Imposta il mese corrente
    int anno = data.get(Calendar.YEAR); // Imposta l’anno corrente

    int ore = data.get(Calendar.HOUR_OF_DAY); // Imposta l’ora corrente
    int minuti = data.get(Calendar.MINUTE); // Imposta il minuto corrente
    int secondi = data.get(Calendar.SECOND); // Imposta il secondo corrente

    // Mostra il risultato su schermo
    System.out.println(giorno + "/" + mese + "/" + anno + " " + ore + ":" + minuti + ":" + secondi);

  • Possiamo osservare l’estrema semplicità con cui riusciamo a recuperare le informazioni che ci servono, infatti, basterà usare il metodo «get()» di «GregorianCalendar» e le costanti della classe «Calendar», per recuperare gli elementi della data da mostrare a video.
  • Per formattare una data riducendo sensibilmente il codice, possiamo sempre adoperare la classe «SimpleDateFormat», vedremo che grazie a questa classe, saremo in grado di trasformare una data da un formato nazionale ad un altro.


29. Gestione delle date

  • Il seguente codice genera un oggetto di tipo «Date» che, grazie al metodo «format()» di «SimpleDateFormat», visualizza la data corrente nel nostro formato.

  • Date data = new Date(); // Dichiarazione e istanza di un oggetto di tipo Date
    SimpleDateFormat formatoIT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); // Imposta il formato
    System.out.println(formatoIT.format(data)); // Mostra il risultato su schermo

  • Nel caso dell’Italia il formato utilizzato sarà di tipo «dd/MM/yyyy»; dove «dd» indica il giorno, «MM» il mese e «yyyy» l’anno, quindi un esempio di data valida per l’Italia sarà: «15/02/1953».
  • Per l’ora il formato sarà «HH:mm:ss»; dove «HH» indica l’ora, «mm» il minuto e «ss» il secondo, un esempio valido sarà «13:00:00».
  • Prestiamo attenzione alla maiuscole e alla minuscole, giacchè «MM» in maiuscolo rappresenta il mese corrente, mentre «mm» in minuscolo rappresenta i minuti nella raffigurazione di un orario.


30. Gestione delle date

  • Per trasformare la data e l’ora in un formato diverso da quello italiano è possibile cambiare pattern, che ad esempio per gli USA sarà di tipo:

    «MM/dd/yyyy hh:mm:ss a Z».

  • Notiamo che «hh» è in minuscolo perché gli americani usano il sistema orario da 12 ore, quindi, per indicare se è mattina o pomeriggio dobbiamo aggiungere la lettera «a» al pattern, inoltre, per essere ancor più precisi, utilizziamo la lettera «Z» per specificare il fuso orario.
  • Un altro modo per convertire una data (a scapito di una superiore personalizzazione del pattern) è quello di usare la classe «Locale», vediamo un esempio pratico in tal senso:

  • Date data = new Date(); // Dichiarazione e istanza di un oggetto di tipo Date
    Locale localeIT = Locale.ITALY; // Dichiarazione e inizializzazione di un oggetto di tipo Locale (ITA)
    Locale localeUSA = Locale.US; // Dichiarazione e inizializzazione di un oggetto di tipo Locale (USA)
    // Imposta il formato italiano e internazionale
    DateFormat formatoIT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, localeIT);
    DateFormat formatoUSA = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, localeUSA);
    System.out.println(formatoIT.format(data)); // Mostra il risultato su schermo (ITA)
    System.out.println(formatoUSA.format(data)); // Mostra il risultato su schermo (USA)

  • Che mostra in output nel momento in cui sto scrivendo:

  • 10/09/17 14.22
    9/10/17 2:22 PM


31. Gestione delle date

  • Per creare un oggetto di tipo «Date» impostando una data e ora a nostra scelta, dobbiamo utilizzare il metodo «parse()» di «SimpleDateFormat» in questo modo:

  • String data = "15/02/1953 13:00:00"; // Imposta la data scelta secondo il pattern di SimpleDateFormat
    SimpleDateFormat formatoIT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); // Imposta il formato

    try {
    Date miaData = formatoIT.parse(data); // Crea un oggetto di tipo Date con la nostra data impostata
    System.out.println(formatoIT.format(miaData)); // Mostra il risultato su schermo
    }
    catch (ParseException ex) {
    Logger.getLogger(Test.class.getName())​.log(Level.SEVERE, null, ex);
    }


  • Ed ecco l’output del codice sorgente:

  • 15/02/1953 13:00:00


32. Gestione delle valute

  • Se abbiamo a che fare con diverse valute, possiamo incorrere nella necessità di rappresentarle nel formato appropriato; anche in questo caso ci viene in aiuto la classe «Locale». Vediamo un esempio:

  • double valuta = 10000.00; // Inizializzazione della valuta da rappresentare
    Locale valutaITA = Locale.ITALY; // Dichiarazione e inizializzazione di un oggetto di tipo Locale (ITA)
    Locale valutaUSA = Locale.US; // Dichiarazione e inizializzazione di un oggetto di tipo Locale (USA)
    NumberFormat formatoIT = NumberFormat.getCurrencyInstance(valutaITA); // Imposta il formato (ITA)
    NumberFormat formatoUSA = NumberFormat.getCurrencyInstance(valutaUSA); // Imposta il formato (USA)
    System.out.println(formatoIT.format(valuta)); // Mostra il risultato su schermo (ITA)
    System.out.println(formatoUSA.format(valuta)); // Mostra il risultato su schermo (USA)

  • Il risultato sarà:

  • € 10.000,00
    $10,000.00


33. La classe «StringTokenizer»

  • Chi è abituato alla programmazione procedurale ricorderà senz’altro l’esigenza, in certe situazioni, di suddividere delle stringhe in più parti, ad esempio per suddividere un percorso che punta ad un file, o semplicemente per dividere dei vocaboli per poi tradurli in un’altra lingua.
  • Per le operazioni di suddivisione delle stringhe si ricopiava o si implementava un algoritmo, con grande dispendio di tempo per il programmatore e di efficienza, giacché nessuno ci assicurava che il codice stilato fosse il più veloce in termini di complessità computazionale.
  • Java ci aiuta nel compito predisponendo una classe chiamata «StringTokenizer», che passata una stringa al costruttore della classe la suddivide in parti detti token.
  • I token possono essere letti attraverso il metodo «hasMoreTokens()», implementato come espressione in una struttura di controllo iterativa.


34. La classe «StringTokenizer»

  • Nel caso in cui non viene passato alcun token al costruttore della classe «StringTokenizer», saranno applicati i seguenti token predefiniti:

  • - « » che indica lo spazio.
  • - «\t» che serve per la tabulazione orizzontale.
  • - «\n» tipicamente usato per andare a capo.
  • - «\r» che serve per il ritorno al carrello (meno usato di «\n»).
  • - «\f» che indica l’avanzamento di pagina.

  • Vediamo il primo esempio d’uso di StringTokenizer, utilizzando i token predefiniti per la suddivisione della frase:

  • StringTokenizer testo = new StringTokenizer("Questo è un test!"); // Stringa da dividere
    while (testo.hasMoreTokens()) { // Lettura dei token nel ciclo while
    System.out.println(testo.nextToken()); // Visualizzazione dei token
    }

  • Che stampa il seguente output:

  • Questo
    è
    un
    test!


35. La classe «StringTokenizer»

  • Vediamo un esempio in cui, questa volta, si specifica un token che, passato al costruttore di «StringTokenizer», consente di suddividere un percorso che punta ad un file:

  • StringTokenizer testo = new StringTokenizer ("C:\\Img\\Domenico.jpg","\\"); // Stringa da dividere
    while (testo.hasMoreTokens()) { // Lettura dei token nel ciclo while
    System.out.println(testo.nextToken()); // Visualizzazione dei token
    }

  • Il codice mostra il seguente output:

  • C:
    Img
    Domenico.jpg

  • Se avessimo settato il terzo parametro del costruttore a true, in questo modo:

  • StringTokenizer testo = new StringTokenizer ("C:\\Img\\Domenico.jpg","\\", true)); // Stringa da dividere
    while (testo.hasMoreTokens()) { // Lettura dei token nel ciclo while
    System.out.println(testo.nextToken()); // Visualizzazione dei token
    }

  • Il risultato sarebbe stato comprensivo di token:

  • C:
    \
    Img
    \
    Domenico.jpg


36. Espressioni regolari

  • Le espressioni regolari ci permettono di analizzare una stringa, inserendo opportuni caratteri speciali in un’altra stringa chiamata «regex».
  • Questi caratteri possono essere utilizzati efficacemente per convalidare dei dati, oppure possono essere utili nel caso intendiamo ricercare una determinata parola.
  • Nella diapositiva seguente, vedremo un elenco esaustivo di questi caratteri (chiamati anche metacaratteri), che ci permetteranno di creare delle particolari funzioni di convalida, ciò non esclude il fatto che è sempre possibile convalidare un dato in modo tradizionale (ad esempio attraverso un «if-else»).


37. Espressioni regolari


Carattere speciale

Descrizione

.

Indica qualsiasi carattere.

*

Indica zero o più occorrenze.

?

Indica zero o una occorrenza.

{…} oppure {… , …}

Indica il numero esatto, minimo, massimo o un intervallo di occorrenze

+

Indica la concatenazione.

[^…]

Indica un insieme negato.

^

Indica l’inizio della stringa.

$

Indica la fine della stringa.

|

Indica l’operatore OR.

\

Serve per indicare i caratteri speciali.

(...)

Contiene una stringa dal valore letterale.

[...]

Contiene un insieme di caratteri.



38. Espressioni regolari

  • Se intendiamo inserire un carattere speciale in una regex usandolo come valore letterale, dobbiamo adoperare il carattere speciale «\». Dunque, se vogliamo accertare la presenza di un punto interrogativo, bisognerà scrivere «\?» e non «?».
  • Passiamo ad alcuni esempi per cominciare a prendere confidenza con le regex:

  • - [aeiou] = Viene soddisfatto quando trova una vocale.
  • - [^aeiou] = Viene soddisfatto quando trova una consonante.
  • - Alessi[ao] = Viene soddisfatto quando trova il nome Alessio o Alessia.
  • - [a-z] = In questo caso è presente un intervallo di caratteri (notare il segno -, sta per “dalla a alla z”), esso è soddisfatto quando viene trovato un qualsiasi carattere minuscolo compreso nell’intervallo.
  • - [0-9] = In questo caso trattasi di un intervallo numerico, viene soddisfatto quando trova un numero compreso tra 0 e 9.
  • - [a-zA-Z_0-9]? = In questo caso è accettato qualsiasi carattere, però sarà soddisfatto se viene convalidato un solo carattere per volta (per via del punto interrogativo).
  • - [a-zA-Z_0-9]* = In questo caso, invece, potranno essere convalidati 0 o più caratteri.
  • - [a-zA-Z_0-9]{3} = Viene soddisfatto se saranno convalidati esattamente 3 caratteri.
  • - [a-zA-Z_0-9]{1-3} = Viene soddisfatto se saranno convalidati da 1 a 3 caratteri.
  • - [a-zA-Z_0-9]{,3} = Viene soddisfatto se saranno convalidati massimo 3 caratteri.
  • - [a-zA-Z_0-9]{3,} = Viene soddisfatto se saranno convalidati minimo 3 caratteri.


39. Espressioni regolari

  • Le parentesi tonde in una espressione regolare indicano una stringa; quindi una regex del tipo «(abc)», viene soddisfatta solo se è presente la sequenza a, b e c nella stringa da analizzare, nel caso delle parentesi quadre «[abc]», invece, si verificava la presenza di uno dei tre caratteri anche in ordine diverso.
  • L’operatore OR «|» permette di scegliere tra più alternative, quindi una espressione del tipo «(alto|medio|basso)» è soddisfatta quando una delle tre parole viene trovata nella stringa da verificare.
  • L’operatore «^» è il più complesso giacché può assumere un duplice significato, se posizionato all’interno delle parentesi quadre, indica la negazione dei caratteri immessi, se posto al difuori delle parentesi, invece, indica l’inizio della stringa, ad esempio l’espressione regolare «^(Ciao)» è verificata solo se la stringa da analizzare inizia con la parola «Ciao».
  • L’operatore «$» indica la fine della stringa, ad esempio un’espressione del tipo «^(Ciao) [a-zA-Z_]$», verifica che la stringa inizi con la parola «Ciao» e finisca con una stringa di caratteri alfabetici (cioè un nome).


40. Espressioni regolari

  • Le espressioni regolari possono dichiarare delle abbreviazioni, che servono ad implementare facilmente funzioni di utilizzo comune:

  • - «\d» equivale a «[0-9]», indica un numero.
  • - «\D» equivale a «[^0-9]», indica una non cifra.
  • - «\s» equivale a «[ \t\n\r]», indica un carattere di spazio.
  • - «\S» equivale a «[^ \t\n\r]», indica un carattere di non spazio.
  • - «\w» equivale a «[0-9A-Za-z]», indica un carattere.
  • - «\W» equivale a «[^0-9A-Za-z]», indica un non carattere.

  • Analogamente, esistono delle abbreviazioni per specifici caratteri:

  • - «[[:alpha:]]» indica qualsiasi lettera, maiuscola o minuscola.
  • - «[[:digit:]]» indica qualsiasi cifra.
  • - «[[:space:]]» indica tutti i caratteri di spazio «[ \t\n\r]».
  • - «[[:upper:]]» indica le lettere maiuscole.
  • - «[[:lower:]]» indica le lettere minuscole.
  • - «[[:punct:]]» indica i caratteri di punteggiatura.
  • - «[[:xdigit:]]» indica i valori esadecimali.


41. Espressioni regolari

  • Finalmente passiamo a verificare un’espressione regolare; procediamo importando la classe «java.util.regex.Pattern» e implementando un metodo statico per la verifica:

  • class Espressione {
    public static boolean verifica(String regex, String input) { // Metodo statico per verificare l’espressione
    if (Pattern.matches(regex, input)) { // Se l’espressione è verificata…
    return true; // Restituisce valore true
    } else { // Altrimenti…
    return false; // Restituisce valore false
    }
    }
    }

  • Il metodo statico invocato inizializzerà una variabile booleana, vediamo come:

  • public class Programma {
    public static void main(String[] args) {
    String input = "test@email.com"; // Stringa da verificare
    String regex = "[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}"; // Stringa che contiene la regex
    boolean verifica = Espressione.verifica(regex, input); //  Inizializzazione della variabile booleana
    System.out.println(verifica==true?​"Verificato":"Errore");// Mostra il risultato su schermo
    }
    }


  • In questo caso: se l’indirizzo e-mail impostato nella stringa «input» è valido, sarà mostrato su schermo il messaggio «Verificato», altrimenti, sarà mostrato il messaggio «Errore».


42. Espressioni regolari

  • Onde evitare di scrivere una regex in modo errato o non conforme, ritengo opportuno mostrare le espressioni regolari più comuni, insomma, quelle che possono tornarci utili nella vita di tutti i giorni:

  • - «[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}» serve per verificare un indirizzo email.
  • - «(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[-/.](19|20)\d\d» serve per verificare una data in formato «dd/MM/yyyy».
  • - «([01]?[0-9]|2[0-3]):[0-5][0-9]» serve per verificare l’ora in formato 24 ore.
  • - «http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?» serve per verificare un URL.
  • - «[a-zA-Z]{6}\d\d[a-zA-Z]\d\d[a-zA-Z]\d\d\d[a-zA-Z]» serve per verificare un codice fiscale.

  • L’osservatore più attento potrebbe aver notato una differenza tra la regex mostrata nel codice java «[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}» e quella mostrata poc’anzi: la differenza consiste nell’aggiunta di un simbolo di backslash. Il primo backslash è necessario alla sintassi java per interpretare il secondo come simbolo di backslash, inoltre, il secondo simbolo di backslash serve alla regex per interpretare il terzo carattere (in questo caso il punto) come valore letterale e non come carattere speciale.


43. Classe «Runtime»

  • La classe «Runtime» ci permette di eseguire un comando del sistema operativo direttamente dal codice java, questo però potrebbe compromettere la portabilità dell’applicazione stessa, infatti, alcuni comandi di MS-DOS non sono validi in ambiente Linux e viceversa.
  • Vediamo un esempio che esegue la calcolatrice su ambiente Microsoft Windows:

  • public class Programma {
    public static void main(String[] args) {
    Runtime run = Runtime.getRuntime();
    try {
    run.exec("calc");
    } catch (Exception ex) {
    System.out.println("Errore su esecuzione del comando.");
    }
    }
    }


44. Classe «Math»

  • Per concludere il nostro tour sulle librerie di utilità, non possiamo non menzionare la classe «Math», essa fornisce un vasto numero di funzioni matematiche che possono tornarci molto utili. Eccone alcune:

  • - «abs(x)» fornisce il valore assoluto di x (double/float/int o long).
  • - «max(x, y)» fornisce il massimo tra due numeri (double/float/int o long).
  • - «min(x, y)» fornisce il minimo tra due numeri (double/float/int o long).
  • - «sin(x)» fornisce il seno del valore x (double).
  • - «cos(x)» fornisce il coseno del valore x (double).
  • - «tan(x)» fornisce la tangente del valore x (double).
  • - «exp(x)» fornisce l’esponenziale del valore x (double).
  • - «sqrt(x)» fornisce la radice quadrata del valore x (double).
  • - «log(x)» fornisce il logaritmo in base e del valore x (double).
  • - «log10(x)» fornisce il logaritmo in base 10 del valore x (double).
  • - «pow(x, y)» fornisce la potenza del valore x (double) elevato y (double).
  • - «ceil(x)» arrotonda per eccesso il valore x (double).
  • - «floor(x)» arrotonda per difetto il valore x (double).
  • - «round(x)» arrotonda il valore x in modo classico (double/float).
  • - «random()» genera un numero casuale di tipo double (compreso tra 0 e 1)


45. Classe «Math»

  • Un esempio interessante di implementazione della classe «Math», può essere quello del confronto tra due numeri per ottenere il valore maggiore, per farlo ci serviremo della funzione «max()», vediamo un esempio:

  • public class Programma {
    public static void main(String[] args) {
    System.out.println(Math.max(18, 12)); // Funzione per restituire il massimo tra due numeri.
    }
    }

  • La funzione restituirà in output il valore «18» che corrisponde al valore massimo.
  • Nulla ci impedisce di creare un nostro algoritmo di confronto, consci del fatto che a livello di complessità computazionale, una funzione della classe «Math» usa un algoritmo uguale se non più efficiente del nostro.