Sei sulla pagina 1di 142

Programmare e Progettare

con Java
Lezione 1 - Rudimenti di Programmazione Java
CHE COS’È JAVA?
CARATTERISTICHE FONDAMENTALI
Il progetto Java ha inizio nel 1991 e vede la sua prima implementazione pubblica
nel 1996 con Java 1.0

Java è un linguaggio di programmazione general-purpose basato su classi,


orientato agli oggetti che fa della portabilità e della sicurezza i suoi maggiori punti
di forza.

La sintassi è molto simile a quella di C/C++.

Funzionalità principare: WORA - Write Once, Run Anywhere.


PRINCIPI DI PROGETTAZIONE
Java è stato realizzato tenendo in mente i seguenti
principi:

1. Deve essere semplice, OO e familiare.


2. Deve essere robusto e sicuro.
3. Deve essere indipendente dall’architettura e
portabile.
4. Deve eseguire ad alte performance.
James Gosling, creatore di Java
5. Deve essere interpretato, divisibile in thread e
dinamico.
WORA
Il codice oggetto prodotto da un compilatore generalmente non risulta essere
portabile. Java ha portato innovazione: WORA.

Più che un principio è uno slogan.

Un programma Java può essere scritto e compilato su un qualsiasi device, ma


potrà anche essere eseguito su un qualsiasi altro. Come? Con la JVM.

Codice compilato in Java prende il nome di Bytecode, traduzione del codice


sorgente pensata per essere eseguita da una JVM.
JAVA VIRTUAL MACHINE
Una macchina virtuale è una emulazione di una macchina reale realizzata in
ambiente virtuale. Le specifiche ne definiscono i dettagli di
implementazione.

Le applicazioni Java possono essere eseguite solo all’interno di una JVM.

Più precisamente, il Bytecode è il linguaggio macchina specifico di una


macchina astratta, eseguito dalla JVM su ogni sistema in grado di
supportare il linguaggio Java.

Java non è il solo linguaggio di programmazione che può produrre Bytecode


Java.

Il Bytecode può essere eseguito su ogni macchina ospitante una JVM.

Questo ne implica la portabilità, ma anche la sicurezza.


SANDBOX
JVM è di fatto una sandbox in cui sistemi runtime permettono l’accesso alla
macchina virtuale stessa (per utilizzarne i servizi) e la collegano al mondo esterno.

Tali sistemi si occupano anche di garantire la sicurezza tramite il


SecurityManager, una classe che si occupa di applicare le policy di sicurezza.

Quando le classi vengono caricate dalla classe ClassLoader all’interno della JVM
vengono controllate da un Bytecode Verifier che ne verifica la legittimità, ma i
controlli continuano anche runtime.
La JVM
APPLETS
Le applet sono piccoli programmi scritti in Java
Bytecode che si possono trovare sulle pagine
web e che vengono eseguiti dalla JVM.

Le applet:

● Non possono accedere al File System locale


● Possono connettersi solo alla sorgente da cui provengono
● Non possono eseguire programmi locali
● Vengono considerati come maliziosi e quindi hanno privilegi minimi
● Non possono manipolare le classi base di Java

In Java 2 sono state introdotte le applet “firmate”.


COMPILATO O INTERPRETATO?
Un linguaggio compilato è un tipo di linguaggio di programmazione che viene tradotto in
linguaggio macchina prima di essere eseguito. Il compilatore si preoccupa di operare questa
traduzione durante la quale segnala eventuali errori o avvertimenti; in caso di errori la
compilazione si ferma! Eventuali errori durante l’esecuzione ne causeranno comunque il termine.

Un linguaggio interpretato invece salta la fase di traduzione in linguaggio macchina e si affida


ad un interprete, un programma in grado di comprendere le istruzioni scritte in un linguaggio di
programmazione ed eseguirle immediatamente. Il programma sarà sempre eseguito dal principio
e si fermerà appena incontrerà un errore sia esso di sintassi che legato all’esecuzione.

Java può essere sia compilato che interpretato a seconda dell’ambiente di esecuzione; più
spesso compilato. Rarissime volte può essere anche eseguito dal processore direttamente.
ERRORI (1)
In questo corso useremo sempre il compilatore Java.
Dopo aver scritto codice, potreste incontrare 2 tipi di errori:
● Errori compile-time: Comprendono errori di sintassi e errori logici che il
compilatore rileva mentre traduce. Il compilatore indica a che riga essi
avvengono e spiega cosa non capisce dando alle volte consigli di risoluzione.
Dato che la compilazione effettua vari cicli, alcuni errori potrebbero essere
rilevati solo dopo la correzione di errori precedenti.
ERRORI (2)
● Errori run-time: Errori spesso generati da situazioni non gestite in cui il
programma si trova a lavorare con dati non previsti o risultati che generano
contraddizioni interne al codice.
HELLO WORLD!
STRUTTURA DI UN PROGRAMMA JAVA
Un programma Java è organizzato come un insieme di classi, le quali
corrispondono a una dichiarazione di tipo o a una collezione di funzioni.

Una classe contiene dichiarazioni di variabili (attributi della classe) e di funzioni


(metodi della classe).

Il programma principale è rappresentato da un metodo speciale: main.

Esso può essere invocato quando si esegue la classe come se fosse


un’applicazione e può creare oggetti, valutare espressioni, invocare altri metodi ed
effettuare qualsiasi altra cosa definisca il comportamento dell’applicazione.
IL MIO PRIMO PROGRAMMA JAVA

● Il nome della classe deve essere uguale al nome del file.


● Per convenzione, il nome della classe inizia con una lettera maiuscola. (Si sta perdendo)
● CamelCase: Ogni parola all’interno del nome di una classe o metodo inizia con una maiuscola. I metodi hanno
la prima parola che comincia con una minuscola.
● Formula magica: public static void main(String[] args)
● Ad ogni istruzione segue “;”
● System.out.println() è un metodo associato al campo out della classe System che opera una stampa a
schermo. Esso prende come argomento una stringa, inserita fra le parentesi.
JDK
JDK è acronimo per Java Development Kit ed è di fatto un insieme di tante
componenti che permettono a noi sviluppatori di realizzare applicazioni usando il
linguaggio Java.
Elemento principale contenuto in JDK è la nostra JVM privata che ci permetterà di
eseguire qualsiasi Bytecode Java.
Da non confondere con SDK, termine più generico e che comprende tools per
realizzare applicazioni di qualsiasi genere utilizzando molteplici linguaggi di
programmazione.
Spesso chiamato anche Java SE.
Esistono molte versioni di JDK, la più recente è la 15.0.2.
COMPONENTI JDK
● javac - Compilatore! Scritto anch’esso in java, accetta codice sorgente scritto
in Java e produce Java Bytecode. Notare che i file prodotti sono di tipo .class!
Come mai?
● java - Loader! Di fatto agisce da interprete, leggendo il Bytecode del file .class
● javadoc - Generatore di documentazione in HTTP.
● jar - Archiviatore, permette di archiviare molteplici classi (più metadati) in un
unico file di tipo .jar
● jdb - Debugger.
INSTALLAZIONE JDK
● Java SE 15:
https://www.oracle.com/java/technologies/javase-jdk15-downloads.html

Avviate ed eseguite.

In caso disinstallate versioni precedenti già presenti.


DOVE PROGRAMMARE?
Ci sono due modi: tramite linea di comando o tramite IDE.
Per sistemi Unix si preferisce usare la prima opzione, per Windows la seconda. Esistono IDE per
tutti i sistemi operativi.
Gli IDE comprendono un editor di testo, usare la linea di comando implica l’uso di un editor di
testo a parte.
Cosa useremo noi:
● ECLIPSE IDE: https://www.eclipse.org/downloads/
● NETBEANS IDE: https://netbeans.apache.org/download/index.html
Editor consigliato:
● SUBLIME TEXT 3: https://www.sublimetext.com/3
INSTALLAZIONE ECLIPSE
INSTALLAZIONE NETBEANS

Potete non installare la parte di PHP


PRIMI ESERCIZI
● Scrivere ed eseguire “Hello, World”
● Modificare il programma così che produca errori di compilazione, cercando di
esplorare il più possibile
LEGGIBILITÀ DEL CODICE
Commentare e indentare il codice non è solo importante. È IMPORTANTISSIMO.

Lavorerete spesso in gruppo: la leggibilità del codice è di massima importanza.


Ogni programmatore ha dei propri standard personali riguardo a nomenclature e
modelli di progetto: dobbiamo farci capire dal prossimo!

L’indentatura è la prima forma di leggibilità: usate TAB!

I commenti differenziano il codice dall’illeggibile al leggibile: usiamo il nostro


linguaggio naturale per rompere le limitazioni di una forma di astrazione più bassa!
COMMENTARE
I commenti vengono ignorati dal compilatore (ma non da altri componenti di JDK o da
plugins!)
Tre tipi:
1. /* commenti */ Commenti su più righe
2. // commenti Commenti su singola riga
3. /** commenti */ Commenti di documentazione
Per i casi 1 e 3, per convenzione si usa un * all’inizio di ogni riga commentata.
VARIABILI
LA VARIABILE
La variabile è un contenitore di dati situato in memoria.

Possono rappresentare i campi di una classe o essere usate come variabili locali
dichiarate all’interno di un blocco ({}) di codice.

Possiamo vedere la variabile come una scatola e il suo valore attuale come il
contenuto al suo interno; contenuto che potrà variare più e più volte durante
l’esecuzione.

In Java le variabili si dichiarano nel modo seguente:

tipo identificatore;
TIPI PRIMITIVI
Valori che possono essere immagazzinati direttamente nella variabile.
In memoria lo spazio è allocato staticamente così che il processore sa interpretare i dati:
dichiarare una variabile significa infatti allocare spazio in memoria!
Tipi primitivi in Java:
● boolean assume solo valore true o false
● char carattere a 16 bit UNICODE
● byte intero a 8 bit con segno
● short intero a 16 bit con segno
● int intero a 32 bit con segno
● long intero a 64 bit con segno
● float numeri in virgola mobile a 32 bit(IEEE 754)
● double numeri in virgola mobile a 64 bit(IEEE 754)
VARIABILE
Possiamo vederla come una scatola con su apposta un’etichetta.

L’etichetta indica il tipo di dato che può stare all’interno della scatola.

Dichiarare la variabile crea la scatola.

ES: int numero;


ASSEGNAMENTO
Dichiarare significa allocare. Assegnare significa riempire.
variabile = valore;
L’operatore “=” opera l’assegnamento, facendo in modo che la variabile assuma il
valore indicato a destra buttando via quello precedente (se esistente).
Le variabili locali sono indefinite finché non subiscono il primo assegnamento:
possibile dichiarare variabili in un punto e assegnarvi un valore in un altro, ma
attenzione: se ci dimentichiamo di assegnare il compilatore si arrabbia!
Siate sempre sicuri che una variabile ottenga un assegnamento SICURAMENTE
prima della fine del blocco dove è stata dichiarata.
ASSEGNAMENTO

ES: numero = 21;


MAESTRI DI VARIABILI
È possibile dichiarare più variabili dello stesso tipo sulla stessa riga, effettuando
assegnamenti iniziali per tutte, nessuna o qualcuna.

Possibile dichiarare più variabili dello stesso valore come:

Possono essere dichiarate ovunque all’interno del codice.

Non hanno valori di inizializzazione di default.

Il compilatore piange se una variabile non ha un assegnamento sicuro.

Cessano di esistere quando l’esecuzione raggiunge la fine del blocco dove sono state dichiarare.
IL MODIFICATORE “FINAL”
Un modificatore è una parola che precede il tipo in una dichiarazione (non solo di
variabile) e che ne modifica le proprietà.

Le variabili hanno un solo modificatore disponibile: la keyword “final”.

final tipo identificatore;

Una variabile final, una volta inizializzata (aka, riceve un assegnamento per la
prima volta) non può più essere modificata.

Tipicamente inizializzata alla dichiarazione (non obbligatorio).


ESERCIZI
● Scrivere un programma che dichiari una variabile per ogni tipo base e
inizializzarle. Stampare a schermo i valori.
● Dichiarare una variabile final e provare a modificarne il valore. Cosa accade?
● Dichiarare una variabile intera e inizializzarla a 5. Dichiarare una seconda
variabile intera e inizializzarla usando il nome della prima (int x = 5; int y = x;).
Stampare y a schermo. Cosa mostra?
● Cosa succede se si assegna a una variabile int una variabile double?
OPERATORI
In Java diversi tipi di operatori:

➢ Aritmetici
➢ Incremento/Decremento
➢ Relazionali
➢ Logici
➢ Manipolatori di bit
➢ Assegnamento
➢ Accesso

...e altri che vedremo a giusto tempo.


OPERATORI ARITMETICI
★ +,-,*,/,%

L’operatore ‘-’ può essere usato singolarmente per invertire il segno: ES: -a

Due tipi di aritmetica:

● Intera: Modulare in complemento a 2: no overflow ma riavvolgimenti.


Troncamento a 0 dei decimali. Divisione per 0 solleva eccezione. char è come
int.
● Virgola mobile: Presente overflow/underflow. Espressioni non valide danno
NaN (not-a-number).
OPERATORI DI INCREMENTO/DECREMENTO
★ ++, --

i++ è come scrivere i = i+1; i-- è come scrivere i = i-1.

Applicabili solo ai tipi base.

L’operatore può essere prefisso (++i) o postfisso (i++). Nel primo caso viene prima
restituito il valore e poi lo si incrementa. Nel secondo caso prima viene
incrementato e poi restituito.

Esplicitando: applicabili anche ai char!


ESERCIZI
● Scrivere un programma che presi due valori (di tipo a vostra scelta) calcolino
il perimetro e area di un triangolo e stamparlo a schermo. Assegnare i valori
direttamente nel codice.
● Utilizzando unicamente gli operatori di incremento/decremento aumentare il
valore di una variabile intera inizializzata a 5 così che tale valore diventi 7 e
stamparne il valore ad entrambi gli incrementi così da visualizzare “5 7”.
OPERATORI RELAZIONALI
★ >, >=, <, <=, ==, !=

Restituiscono valori di tipo boolean (true o false). Utilizzabili con i tipi primitivi
numerici come le normali relazioni matematiche.

In virgola mobile, il confronto tra due NaN dà sempre false.

Solo == e != possono operare tra valori booleani.

Combinabili tra loro.


OPERATORI LOGICI
★ !, &, |, ^

Applicabili a valori booleani (Algebra Booleana…).

Abbiamo già visto: !==not; &==and; |==or.

Non abbiamo visto: ^==xor. Lo xor è un “or esclusivo”: vale true se e solo se un
unico input è true!
SHORT CIRCUIT EVALUATION
★ &&, ||

Esattamente come & e |, ma interrompono la valutazione se il primo valore


determina il valore di verità dell’operazione.

Importante per impedire operazioni non volute se uno dei due valori confrontati è il
risultato di un metodo!
OPERATORI DI MANIPOLAZIONE DEI BIT
★ &, |, ^, <<, >>, >>>
I primi tre effettuano l’operazione equivalente bit a bit. Es:
0xf00f & 0x0ff0 = 0x000 (0xnnnn è un numero esadecimale)
<<, >>, >>> effettuano operazioni di shift dei bit, ovvero spostano i bit nella
direzione indicata.
● << Sposta i bit a sinistra riempiendo con 0 i bit sulla destra: 001 -> 010
● >> Sposta i bit a destra riempiendo a sinistra con il bit più significativo: 001
-> 000; 101 -> 110
● >>> Sposta i bit a destra riempiendo con 0 i bit sulla sinistra: 101 -> 010
OPERATORI DI ASSEGNAMENTO
Abbiamo già visto come si usa l’operatore ‘=’.

Sono combinabili con quelli aritmetici (formano operatori composti).

❖ x += 1 equivale a x = x+1
❖ x *= y+1 equivale a x = x * (y+1)
ESERCIZI
● Scrivere un programma che implementi l’espressione ricavata dalla tabella
della verità del primo esercizio di Algebra Booleana della Lezione 0 e che ne
stampi il risultato. Usare la tabella della verità per verificare la correttezza
dell’esecuzione.
OPERATORE DI ACCESSO ‘.’
Serve per accedere a campi e metodi.

Ad esempio, System.out.println() significa che noi stiamo accedendo al metodo


println() del campo out (che ha un suo tipo! PrintStream) della classe System.

Vedremo più avanti maggiori utilizzi di questo operatore.


PRECEDENZA DEGLI OPERATORI
Operatori in ordine di precedenza per il compilatore (più alto avviene prima).

● Postfissi [] . (parametri) exp++ exp--


● Unari ++exp --exp +exp -exp !
● Creazione o conversione new (tipo)exp
● Moltiplicativi * / %
● Additivi + -
● Scorrimento << >> >>>
● Relazionali < > >= <=
● Uguaglianza == !=
● AND &
● XOR ^
● OR |
● AND in Short Circuit Evaluation &&
● OR in Short Circuit Evaluation ||
● Condizionale ?
● Assegnamenti = += -= *= /= %= >>= <<= >>>= &= ^= |=
ASSOCIATIVITÀ DEGLI OPERATORI
Tutti gli operatori binari sono associativi a sinistra: a+b+c equivale (a+b)+c.
Gli operatori di assegnamento sono associativi a destra: a=b=c equivale a=(b=c).
Associatività e precedenza possono essere sovrascritte dall’uso delle parentesi ( )
ES:
➔ a = b + c prima esegue b+c e poi lo assegna ad a. (a=b)+c prima assegna b
ad a e poi esegue a+c!
➔ !a&b con a e b boolean, a=false e b=false fa prima ! e cambia a in true, poi fa
& e si ha true&false quindi l’espressione dà false. !(a&b) prima fa & e si ha
false&true quindi false, poi fa ! e cambia il risultato dell’espressione in true!
ESERCIZI
Senza scrivere codice, cercare di capire quali sono il tipo e i valori delle
espressioni seguenti:

● 12 < 12 == 6 > 17
● 0xA2F << 4
● i++ + i++ + --i //i = 3 inizialmente
CONVERSIONI DI TIPO
Java è un linguaggio fortemente tipizzato: vengono effettuati controlli di
compatibilità tra i tipi al momento della compilazione così da evitare che vi siano
assegnamenti incompatibili.

Il linguaggio mette a disposizione modi per convertire tipi in altri.

Ci sono conversioni di tipo implicito o esplicito.


CONVERSIONI IMPLICITE
Conversioni che non richiedono alcuna azione da parte del programmatore.
Ogni valore numerico può essere assegnato a una variabile di un tipo numerico
che supporti un insieme di valori più esteso. ES: float può essere assegnato a
double; byte può essere assegnato a int.
Possibile assegnare valori interi a variabili in virgola mobile, ma non viceversa.
ES: int è assegnabile a float; double non è assegnabile a char.
In alcuni casi è possibile assegnare tipi più grandi a variabili più piccole, ma
questo è altamente sconsigliato.
CONVERSIONI ESPLICITE
Anche chiamate cast, permettono di convertire tipi in altri, in genere da tipi più grandi a tipi più piccoli
(operazione sconsigliata se effettuata implicitamente).

Non sempre sono ammesse (ES: boolean non può essere castato a int). Per effettuare un cast:

var_tipo1 = (tipo1) var_tipo2

In questo modo la perdita di informazione avviene in modo controllato e approssimato il più possibile al
valore originale.

Occhio ai cast da double a float! Essi possono:

1. Far perdere precisione.


2. Far ottenere uno 0.
3. Far ottenere un infinito.

I tipi interi subiscono narrow tagliando i bit più significativi.


ESERCIZI
A mano, convertire:

● 289 assegnato a una variabile short (16 bit) in una variabile byte (8 bit).
● 256 assegnato a una variabile short (16 bit) in una variabile byte (8 bit).
● 2559 assegnato a una variabile short (16 bit) in una variabile byte (8 bit).

Riflettete sempre sulle conseguenze delle vostre conversioni! Quando hanno


davvero senso?
TIPI RIFERIMENTO
Tutto ciò che non è un tipo primitivo è un tipo riferimento.
Queste variabile contengono il riferimento (l’indirizzo!) di un oggetto allocato in memoria. Per
questo motivo non si possono normalmente effettuare operazioni tra queste variabili se non
chiamando metodi sui loro contenuti!
Impareremo in prima battuta a gestire questo tipo più complesso di variabili tramite la classe
standard String.
OPERATORI DI UGUAGLIANZA E RIFERIMENTI
Gli operatori di uguaglianza sono applicabili anche ai tipi riferimento, ma la loro
interazione è di un po’ diversa da quella tra tipi base: gli operandi infatti non sono gli
oggetti ma i riferimenti ad essi.

rif1 == rif2 Se e solo se i due tipi riferimento si riferiscono allo stesso oggetto.

true anche se i due riferimenti sono null (ovvero non esistono, non che puntano a null!)

Gli operatori di uguaglianza controllano l’identità dei riferimenti e non l’equivalenza tra
due oggetti referenziati: due riferimenti sono identici se si riferiscono allo stesso oggetto,
mentre due oggetti sono equivalenti se rappresentano logicamente lo stesso valore.

L’equivalenza è controllata dal metodo equals() della classe Object.


METODI
METODI
I metodi sono un modo per dichiarare le operazioni di una classe, ovvero
istruzioni che operano sui dati per ottenere risultati senza fornire dettagli riguardo
tali istruzioni (incapsulamento, vedremo meglio i dettagli nella Lezione 2).

Molti metodi sono già presenti nelle classi standard di Java… e probabilmente
qualcuno nel mondo ha già creato un metodo che fa ciò di cui avete bisogno.

Tuttavia, è importante sapere come si dichiarano, scrivono e invocano i metodi.


DICHIARARE UN METODO (1)
I metodi vanno dichiarati all’interno delle classi, ma la loro dichiarazione non può
essere fatta all’interno di altri metodi.

La dichiarazione di un metodo è composta da due parti: l’intestazione e il corpo.

Il corpo contiene le istruzioni del metodo, mentre l’intestazione ne contiene


modificatori e segnatura, quest’ultima composta da tipo ritornato, nome e
parametri.

Parleremo in modo più approfondito dei modificatori nella Lezione 2.


DICHIARARE UN METODO (2)
Per adesso ci limiteremo a dichiarare metodi come:

public static tipo_ritornato nome_metodo(tipo_param1 param1, tipo_param2 param2…){

//corpo metodo

};

Ad Es: Metodo che fa la somma di due interi.

public static int sommaInt(int a, int b) {

return a+b

Un tipo_ritornato speciale è il void, che indica che il metodo non restituisce nulla ma fa solo operazioni interne.
OVERLOADING DEI METODI
Due metodi possono avere lo stesso nome_metodo se hanno segnature diverse,
quindi un numero OR un tipo diverso di parametri.

Si noti che la segnatura non comprende il tipo di valore restituito, quindi non è
possibile sovraccaricare metodi secondo tale concetto.

ES: public static int sum(int i, int y) public double sum(double i, double y) SI!

public static int sum(int i, int y) public double sum(int i, int y) NO!

Spesso è comodo sovraccaricare metodi per accettare più argomenti, mentre farlo
cambiando i tipi può generare confusione. SEMPRE ATTENTI!
RETURN
All’interno del corpo del metodo deve essere presente almeno una volta (e deve
essere raggiungibile) la keyword return.
Essa causa la terminazione del corpo del metodo e restituisce come output ciò
che è indicato alla sua destra.
Il tipo dell’espressione ritornata deve essere lo stesso del tipo_ritornato dichiarato
nell’intestazione del metodo.
Ogni flusso di esecuzione interna deve finire con un return.
Un metodo che ha tipo_ritornato void usa return; per terminare la propria
esecuzione.
INVOCARE UN METODO
I metodi vengono invocati come operazioni sugli oggetti utilizzando i rispettivi
riferimenti e l’operatore ‘.’ visto a slide 44.

La sintassi per evocare un metodo è:

riferimento.metodo(argomenti)

L’invocazione esegue tutte le istruzioni scritte al suo interno fino al raggiungimento


di un return.
ARGOMENTI
I parametri sono variabili fittizie: essi prendono il valore degli argomenti, ovvero i valori
passati come input del metodo (passaggio per valore). Le operazioni fatte dal metodo sui
parametri non intaccano il valore degli argomenti.
Se viene usato un tipo riferimento come argomento, a passare è il riferimento e non
l’oggetto riferito.
I parametri definiscono il numero e il tipo degli argomenti e gli argomenti vanno passati
nello stesso ordine in cui sono stati dichiarati i parametri perché il metodo 1) parta e 2) si
comporti come voluto.
ES: Un metodo con segnatura void metodo1(int a, boolean b) deve avere argomenti
quali {21, true}. {true, 21} non avrebbe senso, così come non lo avrebbe {77, 75, true}.
NUMERO VARIABILE DI ARGOMENTI
In un metodo l’ultimo parametro all’interno della lista dei parametri può essere dichiarato
sotto forma di una sequenza di un dato tipo.
Per indicare che il parametro è una sequenza lo si dichiara come:
tipo_parametro1… parametro1
Un metodo con un parametro di questo tipo accetta un qualsiasi numero di argomenti di
tipo_parametro1.
ES: void metodo2(boolean a, int… listaInt) può essere invocato con argomenti {true, 1, 2,
3} così come {true, 4, 5, 1, 8, 23}.
Ma come si gestiscono?
Ci manca ancora il concetto di Array che vedremo tra non molto.
IL METODO MAIN
Quando si esegue un programma il sistema ricerca ed esegue il metodo main
della classe chiamata.

Il main ha obbligatoriamente modificatori public static (parole di cui vedremo


presto il significato) e ha come tipo_restituito il void. Può avere un unico
argomento di tipo String[] (un array di Stringhe, concetti che vedremo presto).

In un programma a più classi un qualsiasi numero di classi può avere un metodo


main: verrà inizializzata l’esecuzione dal main della classe passata al compilatore!
ESERCIZI
● Scrivere un metodo che accetta due double come input e che ne ritorna il
risultato della divisione. Chiamare il metodo dal main per verificarne il
funzionamento.
● Scrivere nella stessa classe un metodo con lo stesso nome che effettua la
stessa operazione su due int.
STRUTTURA DI UNA CLASSE
STRUTTURA DI UNA CLASSE
Generalmente una classe segue il seguente template:
STRING, OBJECT, CLASSI INVOLUCRO E
SCANNER
STRING
Tipo di oggetti standard con supporto predefinito all’interno di Java.
La classe String definisce oggetti che rappresentano sequenze immutabili di
caratteri codificati mediante UNICODE. Dopo che una stringa è stata costruita, il
suo contenuto non può più essere modificato, ma la classe String fornisce
tantissimi metodi per lavorare con le stringhe.
È possibile dichiarare implicitamente una stringa usando una sequenza di caratteri
chiusa tra “”.
COSTRUTTORI - INTRODUZIONE
Come vedremo più avanti, esiste una famiglia di metodi speciale chiamata costruttori:
metodi che si occupano di istanziare un oggetto allocando la memoria.
L’operatore new precede i costruttori e si occupa di restituire il riferimento all’oggetto
appena creato.
La maggior parte delle classi ha un costruttore e vedremo come definirli più avanti, per
ora sappiate che stanno alla base della programmazione OO.
I costruttori possono subire overloading.
Useremo la classe String come base per imparare a gestire l’interazione tra classi.
COSTRUTTORI DI STRING
❏ public String() Crea una stringa vuota
❏ public String(String value) Crea una copia di value
❏ public String(StringBuilder value)
❏ public String(StringBuffer value)
Esistono moltissimi costruttori di String. Consultate la documentazione Java per
capire quali sono i migliori.
La documentazione è la risorsa più grande e utile che abbiamo!
Si può scaricare per consultazione offline a:
https://www.oracle.com/java/technologies/javase-jdk15-doc-downloads.html
Disponibile anche online: https://docs.oracle.com/en/java/javase/15/
CONCATENAZIONE DI STRINGHE
L’operatore ‘+’ utilizzato quando uno dei due operandi è una stringa genera una
stringa che concatena quanto viene prima con quanto viene dopo.

Il valore della stringa sopra sarà “Ciao amici!”

Se solo uno dei due operandi è di tipo String, l’altro verrà convertito in modo
implicito in una stringa.

La conversione implicita avviene anche quando si passa un tipo base come


argomento di un metodo parametrizzato per stringhe.
METODI PRINCIPALI
public int length() Restituisce lunghezza della stringa.

public int charAt(int index) Restituisce il carattere nella posizione index della stringa.

public CharSequence Restituisce una CharSequence (nel nostro caso è una stringa)
subsequence(int start, int end) contenente i valori char dalla posizione start a quella end.

public int indexOf(char ch) Restituisce la prima posizione di ch.

public int lastIndexOf(char ch) Restituisce l’ultima posizione di ch.

Controllare la documentazione per eventuali overload.


CONFRONTI TRA STRINGHE
public boolean equals(String s1) true se si passa la stringa riferita da s1 ha lo stesso contenuto.

public boolean equalsIgnoreCase(String Come sopra, ma ignora differenze tra minuscole e maiuscole.
s1)

public boolean Per confrontare diverse CharSequence (vedremo poi le


contentEquals(CharSequence c1) StringBuilder)

public int compareTo(String s1) Restituisce 0 se le stringhe sono uguali, un numero positivo se
la stringa su cui è invocato il metodo segue in ordine
lessicografico quella su cui è invocato e negativo se la precede

public boolean startsWith(String prefix, true se la stringa su cui è invocato il metodo comincia con
int start) prefix (a partire da start, che è omissibile)

public boolean endsWith(String suffix) true se la stringa su cui è invocato il metodo termina con suffix.
COSTRUZIONE DI STRINGHE CORRELATE
public String replace(char oldChar, char Restituisce una nuova String in cui tutti i caratteri oldChar sono
newChar) sostituiti con newChar.

public String trim() Restituisce una nuova String in cui sono rimossi tutti i caratteri
di spaziatura all’inizio e alla fine ( “ ”, “\t”, “\n”)

public String replaceFirst(String regex, Restituisce una nuova String in cui la prima sottostringa che
String repStr) corrisponde a regex viene sostituita da repStr.

public String replaceAll(String regex, Come sopra, ma sono sostituite tutte le sottostringhe.
String repStr)

public String toLowerCase() Restituisce una nuova String equivalente a quella su cui viene
invocato il metodo, ma tutta minuscola.

public String toUpperCase() Come sopra, ma la String sarà tutta maiuscola.


ESERCIZI
● Creare due oggetti String da codice. Stampare per ogni stringa la lunghezza e la
lettera con cui iniziano usando l’operatore di concatenazione.
● Creare un oggetto String dal valore “tre tigri contro tre tigri” e modificarla in modo
tale che ogni occorrenza di “tre” sia sostituita da “due” e ogni occorrenza di “tigri” sia
sostituita da “elefanti”.
● Creare un oggetto String dal valore “supercalifragilistichespiralidoso”. Stampare a
schermo una versione tutta maiuscola della sottostringa che comincia con la prima
‘e’ e finisce con l’ultima ‘r’.
● Creare un oggetto String dal valore “AtterRaGgio” che non abbia lettere doppie.
● Scrivere un programma che data una stringa scriva true se la prima metà della
stringa è uguale alla seconda, false altrimenti. Non usare il costrutto “if” che non
abbiamo ancora visto.
STRINGBUILDER
String → Stringhe immutabili
Stringbuilder → Stringhe costruite a partire da espressioni
COSTRUTTORE:
public StringBuilder() Genera stringa “” e capacità max 16
Può accettare argomenti:
❖ int capacity Capacità max pari a capacity
❖ String str Valore iniziale uguale a quello di str
Consultare la documentazione per altri.
METODI STRINGBUILDER
Supporta praticamente tutti i metodi di String, in più:

public StringBuilder append(String s) Aggiunge s alla fine della stringa.

public StringBuilder insert(int offset, String Inserisce s nella stringa dopo offset caratteri.
s)

public StringBuilder replace(int start, int Rimpiazza i caratteri da start a end (escluso) con s. Se s è
end, String s) più o meno lunga di end-start, la stringa viene adattata.

public String toString(StringBuilder sb) Crea una String dal valore attuale di sb

public void ensureCapacity(int min) Assicura che la capacità del riferimento sia almeno min.

public int capacity() Restituisce la capacità attuale del riferimento.


ESERCIZI
● Creare un oggetto StringBuilder dal valore “”. Fare in modo che il suo valore
diventi “StringBuilder è utile!” e stampare a schermo. Sempre nello stesso
programma, modificare il valore dello StringBuilder a “Java è utile!!” e
stampare a schermo.
OBJECT
Classe alla radice della gerarchia delle classi. Tutte le classi la estendono, ovvero
ne implementano una loro versione dei metodi.

public boolean equals(Object ob) Verifica se l’oggetto riferito è uguale a quello riferito da ob.

public int hashCode() Restituisce un codice hash utilizzabile in tabelle hash.

public String toString() Restituisce uno String che rappresenta l’oggetto. Di base la stringa è
composta da nome della classe, @ e il codice hash in Hex.
CLASSE INVOLUCRO (WRAPPER CLASS)
Una per tipo base, sono classi che contengono un valore del tipo primitivo
corrispondente. Conversioni tra tipi primitivi e loro wrapper class sono impliciti,
ad ES: Integer val = 3;

Qui di seguito, Type si riferirà alla classe involucro del tipo associato, type al
corrispondente tipo primitivo.
COSTRUZIONE
Tutte i Type hanno il seguente costruttore:
public Type(type tipo) Costruisce un Type a partire dal valore “tipo” di tipo type.

Inoltre hanno tutti il seguente metodo:

public static Type valueOf(type tipo) Restituisce un oggetto di tipo Type di valore tipo.
COSTANTI INVOLUCRO
Ogni classe involucro definisce i tre seguenti campi:

public static final type MIN_VALUE Minimo valore rappresentabile per type. Per int è -231

public static final type MAX_VALUE Massimo valore rappresentabile per type. Per int è 231-1

public static final int SIZE Numero di bit utilizzati per rappresentare un valore di questo
tipo. Per int è 32 (4 byte)
METODI INVOLUCRO
public int compareTo(Type other) Restituisce 0 se l’oggetto riferito ha valore uguale a quello
puntato da other, <0 se ha valore minore e >0 se ha valore
maggiore.

public type typeValue() Restituisce il valore primitivo dell’oggetto involucro.

public boolean equals(Object ob) Si spiega da sé

public static parseType(String s) Converte s al valore del tipo primitivo type considerato.
Character non ha questo metodo.

public String toString() Restituisce rappresentazione sotto forma di stringa del valore
dell’oggetto involucro.

public static String toString(type val) Restituisce rappresentazione sotto forma di stringa di val.
CONVERSIONI
TIPO DA STRING A TIPO DA TIPO A STRING

Boolean parseBoolean(String s) toString(boolean bool)

Character // toString(char c)

Byte parseByte(String s) toString(byte b)

Short parseShort(String s) toString(short s)

Integer parseInteger(String s) toString(int i)

Long parseLong(String s) toString(long l)

Float parseFloat(String s) toString(float f)

Double parseDouble(String s) toString(double d)


SCANNER
Richiedere dati in input non è affar facile quanto sembra, dato che non sempre i
dati in ingresso sono quelli attesi o formattati in modo opportuno.

Vedremo più avanti un tipo di Input più comodo, ma per ora vediamo Scanner in
modo ridotto ma funzionale.

Per leggere dati da input serve fare qualche operazione preparativa:

1. Importare la libreria java.util.Scanner


2. Aprire un oggetto di tipo Scanner.
IMPORTARE LIBRERIE
Le librerie sono frammenti di codice già scritto che possono essere collegate al codice oggetto dal linker in fase di linking (appena
dopo la compilazione). In Java esse vengono sotto forma di classi.

L’istruzione standard per importare una libreria in Java è la keyword import e deve essere dichiarata prima della keyword class.

import package/Classe;

Vedremo più avanti il concetto di package.

import è ignorabile se la Classe si trova nella stessa directory della classe chiamante.

La keyword * sostituisce una qualsiasi occorrenza dell’import con tutto ciò che è contenuto a quel livello del package. ES:

import java.util.* Importa tutto il contenuto del pacchetto util del pacchetto java.

Il pacchetto java è standard: incluso in jdk.

È consigliato importare solo ciò che serve davvero.


PREPARARE LO SCANNER
Se si intende chiedere dati all’utente, prima di class si importa:

import java.util.Scanner;

Prima di chiedere i dati, andrà creato un oggetto di tipo Scanner:

Scanner nomeScanner = new Scanner(System.in)

L’argomento di Scanner è la sorgente dei dati. Per ora ci limiteremo a System.in: la linea di comando
dove System.out scrive.
LEGGERE DA INPUT
Una volta che lo Scanner è pronto, non ci resta che chiedere gli input all’utente. Lo
Scanner leggerà ciò che viene scritto da tastiera, ma deve sapere come
interpretarlo. I metodi che effettuano la lettura hanno forma:
public Type nextType()
Per le stringhe, il metodo sarà nextLine().

La classe “Echo”
CHIUDERE LO SCANNER
Ricordate sempre di chiudere lo scanner dopo averlo aperto!

Per ora comprenderne il motivo può essere complicato, ma seguiamo le best


practices e nessuno si fa male!

nomeScanner.close()
ESERCIZI
● Scrivere e provare la classe Echo.
● Usando come base gli esercizi precedenti, modificarli in modo tale che tutti i
valori inizializzati dal codice vengano invece inizializzati dall’utente.
● Scrivere un programma che legga un valore numerico da standard input ma
che lo consideri come una stringa e che quindi ne faccia il quadrato.
Stampare il risultato a schermo.
ARRAY
ARRAY
Un array è una collezione di variabili tutte dello stesso tipo a cui è possibile
accedere mediante semplici indici interi. In Java, gli array sono oggetti.
DICHIARAZIONE: type[] nomeArr = new type[dim] (type nomeArr[])
La dichiarazione vista crea un oggetto di tipo type[] (ovvero, array di tipo type) di
dimensione dim e ne restituisce il riferimento a nomeArr.
Il numero di componenti appartenenti all’array viene determinato al momento della
sua creazione e non della dichiarazione della variabile: nomeArr può cambiare per
riferire un altro array di tipo type di qualsiasi altra lunghezza.
Gli array hanno lunghezza fissa.
ACCESSO
L’accesso ad un array avviene in base alla posizione che i suoi elementi
occupano al suo interno.

Il primo elemento ha indice 0, l’ultimo ha indice lunghezza-1.

nomeArray[ind] Restituisce l’elemento dell’array riferito in posizione ind.

Si può ottenere facilmente la lunghezza di un array utilizzando il suo campo


standard length. Gli array sono oggetti della classe Array!

nomeArray.length Restituisce la lunghezza.


ARRAY DI ARRAY
Possibile avere array i cui elementi siano a loro volta array. Da una dimensione a
più dimensioni!

type[][] nomeMatrix = new type[righe][colonne];

type[][][] nomeMatrix = new type[dim1][dim2][dim3];


INIZIALIZZAZIONE
Quando si crea un array, ogni suo elemento viene inizializzato al valore di default
per il suo tipo. I numeri in genere sono 0, mentre gli oggetti sono null!
L’inizializzazione può essere effettuata mediante le {}:
type[] nomeArray = {val1, val2, val3,...}
ES: String[] animali = {“cane”, “gatto”} Crea array di lunghezza 2.
animali[0] valore: “cane”
animali[1] valore: “gatto”
Simile discorso vale per gli array multidimensionali.
OPERATORI DI INC/DEC E ARRAY
Attenzione a quando si usano gli operatori ++ e -- con gli array!

Spesso vi troverete ad eseguire incrementi come ++array[metodo()], dove


metodo() è un metodo che restituisce un intero che usate come indice.

Bisogna ricordare che ++array[metodo()] = array[metodo()] + 1;

Questo significa che stiamo chiamando metodo() 2 volte e non 1! Se metodo() fa


qualsiasi cosa oltre dare l’intero, tale cosa avverrà due volte.
ARGS (1)
Ora conosciamo gli array: cosa significa quel public static void main(String[] args)
che abbiamo scritto tutte le volte?
Ebbene, args è un array di stringhe la cui lunghezza e contenuto dipende da ciò
che viene passato da linea di comando.
In un terminale, come windows, saranno stringhe che seguono il loading della
classe:

In Eclipse, sono gli Arguments in Run Configurations(tab Arguments).


ARGS (2)

Come si passano tipi base? NON SI PASSANO. Gli args sono solo stringhe!

Però si possono convertire… (usare i vari pars!)


STRING SPLIT
Metodo estremamente utile per gestire flussi di byte!
public String[] split(String separator, int limit)
Interpreta la stringa riferita come un insieme di stringhe separate da una stringa
separator e produce un array di lunghezza massima limit (0 = illimitate) per il
quale ogni posizione contiene un riferimento ad una stringa separata dal metodo.
Ad ES: Data la stringa s=“Ciao---ragazzi---Galdus”, invocare String[] splitted =
s.split(“---”, 0) genererà un array di stringhe in cui:
● splitted[0] = “Ciao”
● splitted[1] = “ragazzi”
● splitted[2] = “Galdus”
ESERCIZI
● Scrivere un programma che legge da linea di comando 4 numeri e che ne
stampa a schermo la media.
CONTROLLO DEL FLUSSO
ISTRUZIONI E BLOCCHI
Due tipi di istruzione:

1. Istruzioni di espressione: Espressioni che computano dati. Terminano con ; e


comprendono:
a. espressioni di assegnamento
b. operatori di incremento (prefissi/postfissi)
c. invocazione di metodo
d. espressioni di creazioni d’oggetto tramite new
2. Istruzioni di dichiarazione: Dichiarano variabili e ne possono inizializzare il valore.
Possono apparire in ogni punto dei blocchi. Le variabili locali hanno uno scope: esistono
solo nel blocco in cui sono state dichiarate e non possono essere chiamate dall’esterno.

I blocchi sono insiemi di 0+ più istruzioni chiuse tra { e }. Un blocco può essere usato laddove si
può utilizzare un’istruzione singola poiché è considerato come un’istruzione composta.
IF-ELSE
if (espressione) istruzione1
else istruzione2
espressione viene valutata come boolean. Se è:
➢ true: esegue istruzione1
➢ false: esegue istruzione2
else è opzionale: se manca e espressione è false, il blocco if non viene eseguito.
istruzione1 e istruzione2 possono essere blocchi.
Possibile aggiungere un altro if all’else, creando l’if-else if-else. Non c’è limite al numero
di if concatenabili.
IF-ELSE IF-ELSE IF-ELSE...
ES:

if (espressione1) istruzione1;

else if (espressione2) istruzione2;

else if (espressione3) istruzione3;

In una situazione come quella sopra, prima valutiamo espressione1: se è true


eseguiamo istruzione1 e saltiamo il resto; altrimenti valutiamo espressione2: se è
true eseguiamo istruzione2 e saltiamo il resto; altrimenti valutiamo espressione3:
se è true eseguiamo istruzione3, altrimenti non eseguiamo nulla.
ESEMPIO IF-ELSE

Notare che l’ultimo if (espressione) poteva essere omesso a favore del solo else.
ESERCIZI
● Scrivere una classe che legge un intero e che stampa “Voto non valido” se
esso non è compreso tra 0 e 30 (compresi). Altrimenti non fa nulla.
● Scrivere un programma che legge un double e che determini se si tratta di un
numero pari o dispari. Stampare a schermo l’esito.
● Implementare l’algoritmo 2 della Lezione 0 (quale dei 3 numeri è maggiore?)
● Implementare l’algoritmo 4 della Lezione 0 (aree di rettangoli)
ESERCIZIO
● Scrivere una classe FrazioniEquivalenti.java che verifica se due frazioni
num1/den1 e num2/den2 sono equivalenti e stampa "equivalenti" o "non
equivalenti", a seconda del caso. Usare il tipo int per i dati in input. Pensate a
una soluzione che non faccia uso di float/double.
OPERATORE ?
Detto operatore condizionale, fornisce un’espressione singola in grado di produrre uno
tra due valori in base alla valutazione di un’espressione di tipo boolean.

value = (userSetIt ? usersValue : defaultValue);

corrisponde a:

if (userSetIt)

value = usersValue;

else

value = defaultValue;
SWITCH
switch (espressione) {
case n: istruzioni
case m: istruzioni

default: istruzioni
}
Si trasferisce il controllo al punto identificato dall’etichetta che corrisponde al risultato
dell’espressione: essa deve essere di tipo intero(byte, short, int o char o una loro classe
involucro) o di tipo enumerativo.
“BLOCCO SWITCH”
Istruzioni del costrutto switch che sono precedute da un’etichetta case associata alla
quale vi è una costante intera o enumerativa. Se il valore di espressione è uguale a una
di queste costanti, il controllo viene passato alla prima istruzione dopo quell’etichetta.
Un’istruzione singola può avere associate più etichette case nel caso debba essere
eseguita in più situazioni:
case n: case m: case i:
istruzione
Se nessuna etichetta corrisponde al valore di espressione, il controllo è passato a alla
prima istruzione che segue l’etichetta default.
Se non vi è un’etichetta default, il blocco switch viene saltato.
INTERROMPERE IL BLOCCO SWITCH
ATTENZIONE! Quando il controllo è passato ad un’etichetta, le istruzioni vengono
eseguite una alla volta dopo quell’etichetta e proseguiranno fino alla fine del
blocco switch!
Se si vuole evitare ciò, al termine delle istruzioni seguenti l’etichetta bisogna
aggiungere la keyword break (le cui applicazioni vedremo più dettagliatamente più
avanti). Incontrare tale parola passa il controllo alla prima istruzione dopo lo
switch.
Se lo switch è definito all’interno di un metodo e le istruzioni di un case
determinano il valore di ritorno del metodo, return può sostituire funzionalmente
break,
ESEMPIO SWITCH
ESERCIZI
● Modificare la classe VocaleConsonante così che gestisca altri casi, quali:
○ ‘c’: ogni lettera ‘c’ di s viene modificata con ‘k’ e a schermo si stampi il valore della nuova
stringa,.
○ ‘y’: si verifica la seconda lettera di s e se essa è una vocale si la si sostituisce con 5, altrimenti
la si cambia con ‘9’.
○ ‘l’: si legge a schermo una stringa e la si confronta con quella originale verificando che siano la
stessa stringa. Stampare a schermo “ok” se sono uguali e “nope” se non lo sono.
● Scrivere una classe NumGiorni che, dato un intero da tastiera, lo interpreti
come un mese dell’anno e stampi a schermo il numero di giorni
corrispondenti. Ad esempio, 11 = Novembre, quindi stampo “30”. Se il valore
dato è fuori dal range [0,12], stampare un messaggio d’errore. In caso il mese
sia Febbraio, chiedere all’utente se l’anno è bisestile o meno e a seconda
della risposta restituire il valore corretto!
WHILE
while (espressione)

istruzione

Il while è un ciclo che ripete l’istruzione finché il valore di espressione (di tipo
boolean o Boolean) risulta true. Il valore è controllato ogni volta che l’ultima
istruzione del blocco viene eseguita.

Quando espressione vale false, il controllo viene dato alla prima istruzione dopo il
while.

Generalmente il valore di espressione viene aggiornato dal ciclo stesso.


DO WHILE
do

istruzione

while(espressione);

Funzionamento analogo al while, ma viene eseguita l’istruzione almeno una volta


poiché espressione è valutata dopo l’ultima istruzione.

In un ciclo while si potrebbe eseguire istruzione anche 0 volte se il valore di


espressione fosse false già inizialmente.
ESEMPIO WHILE
ESERCIZI
● Scrivere un programma che dichiara un array di interi di dimensione 10 e che
chiede all’utente di riempirlo.
● Modificare il programma in modo tale che l’utente possa scegliere la
dimensione dell’array.
● Scrivere un programma che continua a stampare “Ciao!” ogni volta che
l’utente inserisce un carattere diverso da ‘.’, scrivere “Arrivederci!” e terminare
l’esecuzione quando l’utente inserisce ‘.’
FOR (1)
Si presenta in forma base e avanzata.

La base è la più potente e generale delle due e effettua un ciclo dal principio sino alla fine di un intervallo di valori.

for (inizializzazione; ciclo; aggiornamento)

istruzione

Inizializzazione dichiara e/o le variabili di ciclo ed è un’espressione eseguita una sola volta. Possono essere
dichiarate più variabili separate da virgola. Possono essere dichiarate nuove variabili che valgono sono per il ciclo.

Ciclo è un’istruzione booleana valutata prima di eseguire una iterazione: se è true essa viene eseguita, altrimenti no.

Aggiornamento è eseguita al termine di ogni iterazione ed è un’espressione che ha l’obiettivo di aggiornare le variabili
di ciclo.
FOR (2)
Ciclo spesso utilizzato per poter scorrere all’interno di collezioni come gli array.

Si noti che Inizializzazione, Ciclo e Aggiornamento sono tutte omissibili:

➢ Inizializzazione e Aggiornamento evitano di dichiarare variabili di ciclo,


lasciando che Ciclo valuti un'espressione dipendente da valori già presenti
che verranno modificati all’interno del ciclo.
➢ Tutte: Il ciclo for diventa un ciclo for ever:
○ for (;;) istruzione
ESERCIZI
● Ripetere i primi due punti dei precedenti esercizi utilizzando il ciclo for.
● Inizializzare un array con valori interi a piacere. Effettuare una “ricerca
lineare” su di esso chiedendo il valore all’utente.
● Scrivere un metodo che richieda due parametri char e visualizzi tutti i caratteri
compresi tra di essi (estremi esclusi).
FOR EACH
Istruzione for di tipo avanzato che fornisce una forma più compatta per iterare tra i valori
di un insieme.
for (Tipo varCiclo : espressione)
istruzione
espressione è un oggetto che definisce l’insieme dei valori su cui iterare.
varCiclo è una variabile locale di un tipo adatto per il contenuto dell’insieme. Dopo ogni
iterazione assume il valore successivo nell’insieme e viene eseguita l’istruzione e il tutto
viene ripetuto finché tutti gli elementi nell’insieme sono stati scanditi.
Utilizzabile anche con gli oggetti che implementano l’interfaccia Iterable, che vedremo
nella Lezione 2.
ESEMPIO FOR EACH
ESERCIZI
● Individuare quali tra gli esercizi precedenti può essere risolto usando un for
each invece che un normale for e modificarlo così che implementi
quest’ultimo.
NIDIFICARE I CICLI
I cicli sono blocchi e quindi istruzioni: per questo motivo all’interno di un ciclo è
possibile effettuare un qualsiasi numero di altri cicli. Ad esempio:
for (int i = 0; i<4; i++) {
for (int j = 0; j<4; j++) {
boolean b = true;
while (b == true) {
...
Cosa succede?
SCORRERE ARRAY MULTIDIMENSIONALI
I cicli nidificati sono ottimi per scorrere array multidimensionali (aka matrici!).
È possibile scorrere ogni cella di una matrice multidimensionale utilizzando un numero n di cicli
for, dove n è il numero di dimensioni della matrice.
Matrice nxn:
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {}
}
Cosa succede?
(Notare che, banalmente, un array è una matrice unidimensionale! n=1 quindi 1 solo ciclo!
ESEMPIO MATRICE NxM
ESERCIZI
● Replicare il codice dell’esempio precedente. Fare in modo che venga
stampato 1 ogni volta che un valore della matrice è inizializzato.
● Modificare il codice così che l’utente possa scegliere che valore inserire in
ogni cella. Il programma stampa il valore inserito ad ogni passo.
● Modificare ancora il codice così che non venga più stampato ogni volta il
valore, ma facendo in modo che la matrice venga stampata in modo simile al
seguente (matrice 2x3):
ETICHETTE
Le etichette sono nomi dati alle istruzioni per permettere di farvi riferimento. Esse
precedono l’istruzione a cui fanno da nome (ricordate gli switch?):

etichetta: istruzione

ES: saluto: System.out.println(“Ciao!”);

I riferimenti ad un’etichetta possono essere fatti solamente tramite due istruzioni


speciali:

● break;
● continue;
BREAK
break permette di uscire da un qualsiasi blocco di codice. Esiste in due forme:

❖ unlabeled: Scritta solamente come break;, permette di terminare l’esecuzione


del blocco, permettendo di procedere dalla prima istruzione dopo esso.
Spesso usata per uscire da cicli. Necessaria per uscire da cicli infiniti!
❖ labeled: Scritta come break etichetta, permette di interrompere l’esecuzione
del blocco e di saltare all’etichetta, ricominciando l’esecuzione da quel punto.

Alcune raccomandazioni: Non si può usare break labeled come un goto,


ovverosia un modo per saltare dove si vuole nel codice. Entrambe le versioni
vanno usate in modo oculato così da non rendere il codice confuso all’esterno.
CONTINUE
continue può essere usata solo all’interno dei cicli. Il suo significato è semplice:
termina l’iterazione e fa avanzare di 1 il ciclo. Come break, esiste in due forme:

❖ unlabeled: Funziona come scritto sopra.


❖ labeled: continue etichetta, al posto di fare avanzare il ciclo corrente di 1, fa
avanzare quello etichettato. L’etichetta deve quindi riferirsi ad un’istruzione
del ciclo!
RETURN
return termina l’esecuzione di un metodo e ne causa il ritorno del valore che sta
alla destra della keyword.

return val;

Se il metodo non restituisce nulla (aka void) allora si può scrivere return;
JAVA API
API
Le Application Programming Interfaces sono interfacce computazionali (punti di
contatto “logici”) che permettono di far comunicare il vostro codice a specifici SW.
Esse definiscono tutte le chiamate che possono essere fatte ai servizi proposti da tali
SW, come devono essere fatte, quali dati devono essere passati e come.
Java mette a disposizione diversi pacchetti standard per permettere tali interazioni, tutti
quanti racchiusi sotto il package java. Essi contengono Classi, eccezioni e altro.
È possibile trovare la lista completa nella documentazione al seguente link:
https://docs.oracle.com/en/java/javase/15/docs/api/index.html
In questo corso vedremo ne vedremo solo alcuni.
java.io e java.nio
java.io contiene le classi per la gestione dell’I/O, oltre che la manipolazione del
file system. ✓

java.nio contiene le classi che permettono di gestire le operazioni di I/O in modo


alternativo. ✓
java.util
java.util contiene classi di utilità generale, come le classi collezione. ✓

Faremo particolare attenzione a java.util.jar, che definisce classi che permettono


di leggere e scrivere i file nel formato JAR (Java ARchive) basato sul formato
standard ZIP. Essi possono essere usati per distribuire le classi e le risorse
presenti all’interno di un package come unità a sé stanti. Sono accompagnati da
un file descrittivo (manifesto) che memorizza le informazioni riguardanti il
contenuto del jar. ✓
java.applet
java.applet permette di definire le applet, un modo per eseguire codice Java
all’interno di un’altra applicazione (browser wer nel 99% dei casi).

Esse hanno vengono caricate nel browser da un metodo init() che viene invocato
quando la pagina web viene aperta, seguita da un metodo start() che ne fa
effettivamente eseguire le istruzioni.

Se il browser identifica che l’applet non è più utile all’utente (magari perché ha
chiuso la pagina) esso invoca stop() che ne arresta l’esecuzione. Se è deciso che
l’applet non verrà più utilizzata, essa verrà chiusa dall’operazione destroy(),
altrimenti verrà fatta ripartire con start().
java.net e java.sql
java.net fornisce classi che permettono di gestire le infrastrutture necessarie per
gestire il networking come le socket, gli indirizzi di rete, gli URI e gli URL. χ

java.sql fornisce il package JDBC (Java DataBase Connectivity) che permette di


utilizzare i database relazionali. ✓
java.math
java.math è destinato alle classi che permettono di effettuare agevolmente i
calcoli matematici. Al momento comprende 3 classi:

● BigInteger: Operazioni intere a precisione arbitraria.


● BigDecimal: Permette di disporre di un numero decimale dotato di segno e
con precisione arbitraria.
● MathContext: Governa le politiche di arrotondamento.

DA NON CONFONDERE CON JAVA.LANG.MATH!


java.lang
Contiene tutte le classi principali del linguaggio come Object, String, Thread,
Class e Math.

Buona parte del package è importata automaticamente!

Daremo un piccolo sguardo alla classe Math.


java.lang.Math
CAMPI:

❏ E: Il valore più vicino al numero e.


❏ PI: Il valore più vicino a π.

METODI STATICI:

➔ abs(tipo n): Restituisce il valore assoluto di una variabile di tipo numerico.


➔ ceil(double d): Arrotonda all’intero superiore più vicino, restituendo double.
➔ floor(double d): Arrotonda all’intero inferiore più vicino, restituendo double.
➔ max(tipo a, tipo b): Restituisce il massimo tra due valori numerici dello stesso tipo.
➔ min(tipo a, tipo b): Analogo a max.
➔ random(): Restituisce un numero random tra 0 e 1 (compresi) come double.
➔ sqrt(double a): Restituisce la radice quadrata di a come double.

PRECAUZIONI D’USO:

1. Importare sempre il metodo voluto dichiarando nell’import space: import java.lang.Math.nomeMetodo;


2. Occhio ai tipi! Realizzate conversioni sicure!
ESERCIZI
● Calcolare l’area di un cerchio chiedendo il raggio da standard input.
● Generare un numero random tra 0 e 1. Prendere un numero da standard
input e moltiplicare per il numero random generato. Fare in modo che il
risultato sia sempre positivo a prescindere dal valore inserito dall’utente (che
può inserire anche valori negativi).
● Calcolare la lunghezza dell’ipotenusa di un triangolo rettangolo dati i cateti,
raccolti da standard input.
SOMMARIO
In questa lezione abbiamo visto:
● JDK, JVM e Java Sandbox
● Variabili e operatori
● Metodi
● Struttura di una classe
● Classi utili del pacchetto java.lang come String, Object, le classi involucro.
Classe Scanner del pacchetto java.util.
● Array
● Controllo del Flusso
● API

Potrebbero piacerti anche