Esercizi
- Home
- Esercizi Capitolo 4
Capitolo 4
Operatori e Gestione del flusso di esecuzione
Dopo aver studiato il capitolo 4 dovremmo già essere in grado di poter scrivere programmi usando il
linguaggio Java. Quello che manca ancora sono le nozioni di Object Orientation che si studieranno
per bene a
partire dal prossimo capitolo. Intanto prendiamo dimestichezza con il flusso di esecuzione.
Di seguito trovate gli esercizi del capitolo.
Per
ogni esercizio, cliccando sulla traccia potete vedere la relativa soluzione.
Gli esercizi caratterizzati dall'icona sono
considerati i più complessi relativamente agli argomenti trattati.
Se preferite lavorare offline, è possibile scaricare tutti gli esercizi e le relative
soluzioni in formato PDF nella sezione download.
-
Esercizio 4.a)
Scrivere un semplice programma, costituito da un'unica classe, che sfruttando esclusivamente un cicloinfinito, l'operatore modulo, due costrutti
if
, unbreak
ed uncontinue
, stampi solo i primi cinque numeri pari.
Soluzione
Di seguito viene listata una classe che aderisce ai requisiti richiesti:
public class TestPari { public static void main(String args[]) { int i = 0; while (true) { i++; if (i > 10) break; if ((i % 2) != 0) continue; System.out.println(i); } } }
Nel metodomain
dichiariamo prima una variabilei
che fa da indice e che inizializziamo a0
. Poi dichiariamo il ciclo infinitowhile
, la cui condizione è sempretrue
. All'interno del ciclo incrementiamo subito di un'unità il valore della variabilei
. Poi controlliamo se il valore della suddetta variabile è maggiore di10
, se la risposta è sì, il costruttobreak
seguente ci farà uscire dal ciclo che doveva essere infinito, e di conseguenza il programma terminerà subito dopo. Nel caso invecei
valesse meno di10
, utilizzando l'operatore modulo (%
) si controlla se il resto della divisione trai
e2
è diverso da0
. Ma tale resto sarà diverso da0
se e solo sei
è un numero dispari. Se quindi il numero è dispari, con il costruttocontinue
passeremo alla prossima iterazione partendo dalla prima istruzione del ciclowhile
(i++
). Se invecei
è un numero pari, allora esso verrà stampato.
L'output del precedente programma è il seguente:
2 4 6 8 10
-
Esercizio 4.b)
Scrivere un'applicazione che stampi i 26 caratteri dell'alfabeto (inglese) con un ciclo.
Soluzione
public class TestArray { public static void main(String args[]) { for (int i = 0; i < 26; ++i) { char c = (char)('a' + i); System.out.println(c); } } }
Si esegue un ciclo con l'indicei
che varia da0
a25
. Aggiungendo al carattere'a'
il valore dell'indicei
(che ad ogni iterazione si incrementa di un'unità), otterremo gli altri caratteri dell'alfabeto. Il cast achar
è necessario perché la somma tra un carattere ed un intero viene promosso ad intero. -
Esercizio 4.c)
Scrivere una semplice classe che stampi a video la tavola pitagorica.
Suggerimento 1: non sono necessari array.
Suggerimento 2: il metodoSystem.out.println
stampa l'argomento che gli viene passato e poi sposta il cursore alla riga successiva; infattiprintln
sta per "print line". Esiste anche il metodoSystem.out.print
che invece stampa solamente il parametro passatogli.
Suggerimento 3: sfruttare un doppio ciclo innestato.
Soluzione
Il listato potrebbe essere il seguente:
public class Tabelline { public static void main(String args[]) { for (int i = 1; i <= 10; ++i) { for (int j = 1; j <= 10; ++j) { System.out.print(i*j + "\t"); } System.out.println(); } } }
Con questo doppio ciclo innestato ed utilizzando il carattere di escape di tabulazione (\t
), riusciamo a stampare la tavola pitagorica con poche righe di codice. -
Esercizio 4.d) Operatori e flusso di esecuzione, Vero o Falso:
1. Gli operatori unari di pre-incremento e post-incremento applicati ad una variabile danno lo stesso risultato, ovvero se abbiamo:
siaint i = 5;
siai++;
++i;
aggiornano il valore di
i
a6
;
2.d += 1
è equivalente ad++
, doved
è una variabiledouble
.
3. Se abbiamo:int i = 5; int j = ++i; int k = j++; int h = k--; boolean flag = ((i != j) && ( (j <= k ) || (i <= h)) );
flag
avrà valorefalse
.
4. L'istruzione:System.out.println(1 + 2 + "3");
stamperà
33
.
5. Il costruttoswitch
può in ogni caso sostituire il costruttoif
.
6. L'operatore ternario può in ogni caso sostituire il costruttoif
.
7. Il costruttofor
può in ogni caso sostituire il costruttowhile
.
8. Il costruttodo
può in ogni caso sostituire il costruttowhile
.
9. Il costruttoswitch
può in ogni caso sostituire il costruttowhile
.
10. I comandibreak
econtinue
possono essere utilizzati nei costruttiswitch
,for
,while
edo
ma non nel costruttoif
.
Soluzione
1. Vero.
2. Vero.
3. Falso, la variabile booleanaflag
avrà valoretrue
. Le espressioni atomiche valgono rispettivamentetrue
-false
-true
, sussistendo le seguenti uguaglianze:i = 6
,j = 7
,k = 5
,h = 6
. Infatti (i != j
) valetrue
e inoltre (i <= h
) valetrue
. L' espressione( (j <= k ) || (i <= h)) )
valetrue
, sussistendo l'operatore OR. Infine l'operatore AND fa sì che la variabileflag
valgatrue
.
4. Vero.
5. Falso,switch
può testare solo una variabile intera (o compatibile) confrontandone l'uguaglianza con costanti (in realtà dalla versione 5 si possono utilizzare come variabili di test anche le enumerazioni e il tipoInteger
, e dalla versione 7 anche le stringhe). Il costruttoif
permette di svolgere controlli incrociati sfruttando oggetti, espressioni booleane etc.
6. Falso, l'operatore ternario è equivalente ad un'espressione che restituisce un valore. In particolare produce sempre un valore, e questo deve essere per forza assegnato o utilizzato in qualche modo (assegnandolo ad una variabile, passandolo come argomento ad un metodo, etc.). Per esempio, sei
ej
sono due interi, la seguente espressione:i < j ? i : j;
provocherebbe un errore in compilazione (oltre a non avere senso), visto che il risultato non viene sfruttato.
7. Vero.
8. Falso, ildo
in qualsiasi caso garantisce l'esecuzione della prima iterazione sul codice. Ilwhile
potrebbe prescindere da questa soluzione.
9. Falso, loswitch
è una condizione non un ciclo.
10. Falso, ilcontinue
non si può utilizzare nelloswitch
ma solo nei cicli. -
Esercizio 4.e)
Modificare la classe
TestArgs
creata nell'esercizio 3.g, in modo tale da evitare eccezioni al runtime, con un costrutto imparato in questo capitolo.
Soluzione
Il listato potrebbe essere il seguente:
public class TestArgs { public static void main(String args[]) { if (args.length == 1) { System.out.println(args[0]); } else { System.out.println("Specificare un valore da riga di comando"); } } }
-
Esercizio 4.f)
È buona norma aggiungere la clausola
default
ad un costruttoswitch
. Sapreste spiegare perché?
Soluzione
Questo perché non sappiamo a priori come si evolverà il nostro programma, e quindi, anche se nel momento in cui si scrive il programma potrebbe non essere necessario la clausola
default
, modificando il programma potrebbe nascere una nuova condizione non prevista, creando un baco nella nostra applicazione. Infatti il nuovo caso non sarà contemplato e il flusso di esecuzione non entrerà in nessuna clausola del costruttoswitch
. Anche usare il costruttodefault
solo per stampare una frase "Caso non previsto" potrebbe essere una buona abitudine. -
Esercizio 4.g)
È buona norma aggiungere la clausola
else
ad un costruttoif
. Sapreste spiegare perché?
Soluzione
La risposta è identica alla precedente. La clausola
else
per unif
è equivalente a una clausoladefault
per loswitch
. -
Esercizio 4.h)
Creare una classe con un metodo
main
che, utilizzando un ciclofor
, selezioni i primi 10 numeri divisibili per 3, e li stampi dopo averli concatenati con una stringa in modo tale che l'output del programma sia:
Numero multiplo di 3 = 3 Numero multiplo di 3 = 6 Numero multiplo di 3 = 9 Numero multiplo di 3 = 12 Numero multiplo di 3 = 15 Numero multiplo di 3 = 18 Numero multiplo di 3 = 21 Numero multiplo di 3 = 24 Numero multiplo di 3 = 27 Numero multiplo di 3 = 30
Soluzione
Il listato richiesto potrebbe essere il seguente:
public class Esercizio4H { public static void main(String args[]) { for (int i = 1, j = 1; j <= 10; i++) { if (i % 3 == 0) { System.out.println("Numero multiplo di 3 = " + i); j++; } } } }
-
Esercizio 4.i)
Ripetere l'esercizio 4.h usando un ciclo
while
invece del ciclofor
.
Soluzione
Il listato richiesto potrebbe essere il seguente:
public class Esercizio4I { public static void main(String args[]) { int i = 1, j = 1; while (j <= 10) { if (i % 3 == 0) { System.out.println("Numero multiplo di 3 = " + i); j++; } i++; } } }
-
Esercizio 4.j)
Ripetere l'esercizio 4.h usando un ciclo
do
-while
invece del ciclofor
.
Soluzione
Il listato richiesto potrebbe essere il seguente:
public class Esercizio4J { public static void main(String args[]) { int i = 1, j = 1; do { if (i % 3 == 0) { System.out.println("Numero multiplo di 3 = " + i); j++; } i++; } while(j <= 10); } }
-
Esercizio 4.k)
Creare una classe chiamata
PariODispari
che definisca una metodo chiamatodammiPariODispari
, che restituisca in maniera casuale la stringa "Pari" o "Dispari". Creare anche una classe di test che invocando tale metodo stampi il risultato.Suggerimento: vedere al soluzione dell'esercizio 3.v.
Soluzione
Il codice della classe
PariODispari
richiesto potrebbe essere il seguente:import java.util.*; public class PariODispari { public String dammiPariODispari() { Random random = new Random(); return random.nextInt() % 2 == 0 ? "Pari" : "Dispari"; } }
Notare che abbiamo usato un operatore ternario perché più adatto alla situazione, ma avremmo potuto utilizzare anche un semplice costruttoif
.Mentre il codice della classe che
TestPariODispari
potrebbe essere il seguente:
public class PariODispariTest { public static void main(String args[]) { PariODispari pariODispari = new PariODispari(); System.out.println(pariODispari.dammiPariODispari()); } }
-
Esercizio 4.l)
Sfruttando la classe
PariODispari
creata nell'esercizio precedente, creare una classe chiamataTestaOCroce
che definisca un metodo chiamatodammiTestaOCroce
che utilizzando un'espressioneswitch
, restituisca la stringa "Testa" o "Croce". Creare anche una classe di test che invocando tale metodo stampi il risultato.
Soluzione
Il codice della classe
TestaOCroce
richiesto potrebbe essere il seguente:
public class TestaOCroce { public String dammiTestaOCroce() { PariODispari pariODispari = new PariODispari(); String pariODispariString = pariODispari.dammiPariODispari(); String testaOCroce = switch (pariODispariString) { case "Pari" -> "Testa"; case "Dispari" -> "Croce"; default -> "C'è un Bug!!!"; }; return testaOCroce; } }
mentre il codice della classe che
TestaOCroceTest
potrebbe essere il seguente:
public class TestaOCroceTest { public static void main(String args[]) { TestaOCroce testaOCroce = new TestaOCroce(); System.out.println(testaOCroce.dammiTestaOCroce()); } }
-
Esercizio 4.m)
Si consideri il seguente codice:
import java.util.Scanner; public class ProgrammaInterattivo { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); String stringa = ""; System.out.println("Digita qualcosa e batti enter, oppure scrivi " + "\"fine\" per terminare il programma"); while(!(stringa = scanner.next()).equals("fine")) { System.out.println("Hai digitato " + stringa.toUpperCase() + "!"); } System.out.println("Fine programma!"); } }
Questa classe legge l'input da tastiera mediante la classe
Scanner
del packagejava.util
. Il metodonext
usato nel costruttowhile
(con una sintassi complessa che comprende anche l'assegnazione alla variabile stringa) è un metodo bloccante (ovvero che blocca l'esecuzione del codice in attesa di input da parte dell'utente) che legge l'input da tastiera sino a quando si preme il tasto "enter" ("invio"). Il programma termina quando si digita la parola "fine".
Attenzione che i metodi bloccanti diScanner
leggono le pressioni dei tasti. Questo significa che a volte troveremo caratteri non riconosciuti in output, in corrispondenza della pressione di tasti come "Maiuscolo", o "Canc".
Modificare il programma precedente in modo tale che diventi un moderatore di parole, ovvero che censuri alcune parole digitate.
Eseguire l'esercizio solo censurando le parole digitate singolarmente (non all'interno di una frase), a meno che non si è convinti di essere in grado di farlo (eventualmente la documentazione è come sempre a vostra disposizione per cercare metodi utili alla causa).
Soluzione
Il listato richiesto potrebbe essere il seguente:
import java.util.Scanner; public class Moderatore { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); String stringa = ""; System.out.println("Digita qualcosa e batti enter, oppure scrivi " + "\"fine\" per terminare il programma"); while (!(stringa = scanner.next()).equals("fine")) { stringa = moderaStringa(stringa); System.out.println("Hai digitato " + stringa.toUpperCase() + "!"); } System.out.println("Fine programma!"); } private static String moderaStringa(String stringa) { switch (stringa) { case "accipicchiolina": case "perbacco": case "stupidino": case "giulivo": case "giocondo": case "perdindirindina": stringa = "CENSURATA!"; break; default: break; } return stringa; } }
È solo una delle soluzioni (non di certo la più elegante). -
Esercizio 4.n)
Quali dei seguenti operatori può essere utilizzato con variabili booleane?
1.
+
2.%
3.++
4./=
5.&
6.=
7.!!
8.>>>
Soluzione
Elenchiamo tutti i casi:
1.
+
se inteso come operatore di addizione no, ma come operatore di concatenazione di stringhe permette di concatenare una stringa a un booleano.
2.%
no
3.++
no
4./=
no
5.&
sì, per esempio(true & false) = true
.
6.=
sì, è un operatore di assegnazione, applicabile a qualsiasi tipo.
7.!!
non è un operatore.
8.>>>
no
-
Esercizio 4.o)
Qual è l'output del seguente programma?
public class Esercizio4O { public static void main(String args[]) { int i = 99; if (i++ >= 100) { System.out.println(i+=10); } else { System.out.println(--i==99?i++:++i); } } }
Scegliere tra le seguenti opzioni:
1.10
2.101
3.99
4.110
Soluzione
La risposta corretta è:
99
.
Infattii
inizialmente vale99
. Poi nella condizione del primoif
, viene usato un operatore di post-incremento, il quale avendo minore priorità rispetto all'operatore>=
viene eseguito dopo di esso. Questo implica chei
vale ancora99
quando viene testato se è>= 100
, e solo dopo il test viene incrementato a100
. Quindi la condizione dell'if
èfalse
, e non viene eseguito il relativo blocco di codice. Quindi viene eseguito il blocco di codice della clausolaelse
. Qui viene stampato il risultato di un operatore ternario. Infatti viene decrementato il valore dii
da100
a99
, e quindi l'operatore ternario ritorna il primo valore, ovveroi++
. Anche in questo caso si tratta di un operatore di post-incremento (a bassa priorità), e quindi viene prima stampato il valore dii
(99
) e poi incrementata la variabile (ma tanto il programma termina subito dopo). -
Esercizio 4.p)
Qual è l'output del seguente programma?
public class Esercizio4P { public static void main(String args[]) { int i = 22; int j = i++%3; i = j!=0?j:i; switch (i) { case 1: System.out.println(8<<2); case 0: System.out.println(8>>2); break; case 2: System.out.println(i!=j); break; case 3: System.out.println(++j); break; default: System.out.println(i++); break; } } }
Scegliere tra le seguenti opzioni:1.24
2.6
e al rigo successivo10
3.10
4.true
5.false
6.22
7.21
8.32
e al rigo successivo2
Soluzione
La risposta corretta è:
32
e al rigo successivo2
, ovvero l'output è il seguente:
32 2
Infatti inizialmente
i
vale22
, ej
vale quanto il resto di22
(e non23
perché il post-incremento viene applicato dopo l'operatore modulo%
) diviso3
, ovvero1
. Dopodiché adi
viene assegnato il valore di ritorno dell'operatore ternario che controlla sej!=0
(e lo è). Quindi viene ritornato il valore dij
che è1
. Nel costruttoswitch
si entra nelcase 1
dove viene stampato8<<2
, che equivale a8
moltiplicato per2
alla seconda, ovvero32
. Inoltre viene eseguito anche ilcase 0
, visto che non c'è unbreak
che fa uscire dal costrutto. Quindi viene stampato8>>2
che equivale a8
diviso2
alla seconda, ovvero2
. -
Esercizio 4.q)
Si scriva un programma che chieda all'utente di inserire il numero di giorni passati dall'ultima vacanza fatta. Una volta inserito questo numero, il programma dovrà rispondere quanti minuti sono passati dall'ultima vacanza.
Soluzione
Il listato potrebbe essere il seguente:
import java.util.Scanner; public class Esercizio4Q { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println("Digita il numero di giorni passati dall'ultima vacanza"); int giorni = scanner.nextInt(); System.out.println("Hai digitato " + giorni + " giorni!"); int ore = giorni*24; int minuti = ore*60; System.out.println("Quindi sono passati " + minuti + " minuti!"); } }
-
Esercizio 4.r)
Data la seguente classe:
public class Esercizio4R { private static int matrice[][] = { {1, 7, 3, 9, 5, 3}, {6, 2, 3}, {7, 5, 1, 4, 0}, {1, 0, 2, 9, 6, 3, 7, 8, 4} }; public static void main(String args[]) { } }
implementare il metodo
main
in modo che legga un numero (tra0
e9
) come parametroargs[0]
, e trovi la posizione (riga e colonna) della prima occorrenza del numero specificato all'interno dell'array bidimensionale denominatomatrice
.
Soluzione
La soluzione potrebbe essere la seguente:
public class Esercizio4R { private static int matrice[][] = { {1, 7, 3, 9, 5, 3}, {6, 2, 3}, {7, 5, 1, 4, 0}, {1, 0, 2, 9, 6, 3, 7, 8, 4} }; public static void main(String args[]) { int numeroDaTrovare = Integer.parseInt(args[0]); PRIMA_LABEL: for (int i = 0; i < matrice.length; i++) { int[] riga = matrice[i]; for (int j = 0; j < riga.length; j++) { if (riga[j] == numeroDaTrovare) { System.out.println(numeroDaTrovare +" trovato a riga = " + ++i + ", colonna = " + ++j); break PRIMA_LABEL; } } } System.out.println("Ricerca terminata"); } }
Abbiamo dapprima dovuto convertire
args[0]
tramite il metodo statico della classeInteger
parseInt
(cfr. esercizio 3.t) immagazzinandolo in una variabilenumeroDaTrovare
. Poi abbiamo utilizzato un doppio ciclo innestato per navigare all'interno delle celle della matrice, sfruttando gli indicii
(per le righe) ej
(per le colonne). Si noti l'utilizzo della label che abbiamo chiamatoPRIMA_LABEL
, che marca il ciclo esterno. Quando viene trovata la prima occorrenza del numero da trovare, l'istruzione:
break PRIMA_LABEL;
fa terminare anche il ciclo esterno, e il programma continua stampando il messaggio
Ricerca terminata
, e poi termina. -
Esercizio 4.s)
La soluzione dell'esercizio precedente fallisce nel momento in cui:
• non si specifica un argomento da riga di comando;
• si specifica da riga di comando un argomento intero che non rientra nel range0
-9
;
• si specifica da riga di comando un argomento che non è un numero intero;Aggiungere, alla soluzione dell'esercizio 4.r, il codice che gestisce i tre casi (specificando un messaggio con le istruzioni da seguire per il corretto utilizzo).
Il terzo caso può essere gestito con quanto studiato finora, ma più avanti studieremo dei metodi per semplificare il nostro codice. In particolare nel capitolo 8 dove si parla di gestione delle eccezioni, e nell'appendice G in cui parleremo delle regular expression, vedremo che esistono delle soluzioni piuttosto semplici per gestire il terzo caso.
Soluzione
Il listato potrebbe essere il seguente:
public class Esercizio4S { private static int matrice[][] = { {1, 7, 3, 9, 5, 3}, {6, 2, 3}, {7, 5, 1, 4, 0}, {1, 0, 2, 9, 6, 3, 7, 8, 4} }; public static void main(String args[]) { int numeroDaTrovare = controllaArgomento(args); if (numeroDaTrovare == -1) { System.out.println("Specificare un numero intero compreso tra" + " 0 e 9"); return; } PRIMA_LABEL: for (int i = 0; i < matrice.length; i++) { int[] riga = matrice[i]; for (int j = 0; j < riga.length; j++) { if (riga[j] == numeroDaTrovare) { System.out.println(numeroDaTrovare + " trovato a riga = " + ++i + ", colonna = " + ++j); break PRIMA_LABEL; } } } System.out.println("Ricerca terminata"); } private static int controllaArgomento(String[] args) { if (args.length == 1) { if (args[0].length() == 1) { for (int i = 0; i < 10; i++) { if (args[0].equals("" + i)) { return Integer.parseInt(args[0]); } } } } return -1; } }
Si noti che abbiamo delegato al metodo
controllaArgomento
la correttezza dell'input specificato dall'utente. Tale metodo ritorna il valore specificato, oppure, nel caso non sia corretto, il valore-1
. Come è possibile vedere dal codice del metodomain
, nel caso il valore ritornato dal metodocontrollaArgomento
sia-1
, viene stampato un messaggio di istruzioni per l'utente, e con l'istruzionereturn
, si esce dal metodo. Si noti che il metodomain
ritornavoid
, quindi per uscire dal metodo si usa l'istruzionereturn
senza specificare cosa ritornare.
Analizziamo ora il metodocontrollaArgomento
. Con il primoif
abbiamo dapprima controllato che la lunghezza dell'arrayargs
sia1
, ovvero che sia stato specificato un unico argomento, utilizzando la variabilelength
dell'array (cfr. paragrafo 3.6.5). Con il secondoif
abbiamo controllato che la lunghezza della stringaargs[0]
sia esattamente1
. Abbiamo sfruttato la chiamata al metodolength
della classeString
(da non confondersi con la variabilelength
dell'array). Il ciclofor
seguente esegue un ciclo su valori che vanno da0
a9
, e controlla cheargs[0]
coincida con uno dei valori. Nel momento in cui trova una corrispondenza, il valore corrente viene ritornato dopo averlo convertito a intero mediante la chiamata al metodo statico della classeInteger
parseInt
(cfr. esercizio 3.t). Se invece nel ciclofor
non si trovano corrispondenze, per esempio perché è stata specificata una lettera o un simbolo (quindi non un intero compreso tra0
e9
), allora il ciclo terminerà e sarà ritornato il valore-1
. -
Esercizio 4.t)
Dichiarare una classe
CalcolatriceSemplificata
che dati due numeri definisca i metodi per:• Sommarli.
• Sottrarre il secondo dal primo.
• Moltiplicarli.
• Dividerli.
• Restituire il resto della divisione.
• Restituire il numero più grande (il massimo).
• Restituire il numero più piccolo (il minimo).
• Restituire la media dei due numeri.
Creare una classe che testa il funzionamento di tutti i metodi.
Soluzione
La classe
CalcolatriceSemplificata
richiesta potrebbe essere simile alla seguente:public class CalcolatriceSemplificata { public double somma(double d1, double d2) { return d1 + d2; } public double sottrai(double d1, double d2) { return d1 - d2; } public double moltiplica(double d1, double d2) { return d1 * d2; } public double dividi(double d1, double d2) { return d1 / d2; } public double restituisciResto(double d1, double d2) { return d1 % d2; } public double massimo(double d1, double d2) { return d1 > d2 ? d1 : d2; } public double minimo(double d1, double d2) { return d1 > d2 ? d2 : d1; } public double media(double d1, double d2) { return (d1 + d2)/2; } }
Mentre la classe per il suo test potrebbe essere:
public class Esercizio4T { public static void main(String args[]) { CalcolatriceSemplificata calcolatriceSemplificata = new CalcolatriceSemplificata(); System.out.println("42.7 + 47.8 = " + calcolatriceSemplificata.somma(42.7, 47.8)); System.out.println("42.7 - 47.8 = " + calcolatriceSemplificata.sottrai(42.7, 47.8)); System.out.println("42.7 x 47.8 = " + calcolatriceSemplificata.moltiplica(42.7, 47.8)); System.out.println("42.7 : 47.8 = " + calcolatriceSemplificata.dividi(42.7, 47.8)); System.out.println("il resto della divisione tra 42.7 e 47.8 è " + calcolatriceSemplificata.restituisciResto(42.7, 47.8)); System.out.println("Il massimo tra 42.7 e 47.8 è " + calcolatriceSemplificata.massimo(42.7, 47.8)); System.out.println("Il minimo tra 42.7 e 47.8 è " + calcolatriceSemplificata.minimo(42.7, 47.8)); System.out.println("La media tra 42.7 e 47.8 è " + calcolatriceSemplificata.media(42.7, 47.8)); } }
-
Esercizio 4.u)
Dichiarare una classe che utilizza la classe
Scanner
, che permette all'utente di interagire con la classeCalcolatriceSemplificata
: l'utente deve poter scrivere il primo operando, selezionare da una lista l'operazione da eseguire e specificare il secondo operando. Il programma deve restituire il giusto risultato.
Attenzione che i metodi bloccanti diScanner
leggono le pressioni dei tasti. Questo significa che a volte troveremo caratteri non riconosciuti in output, in corrispondenza della pressione di tasti come "Maiuscolo", o "Canc".
Soluzione
Il listato richiesto potrebbe essere il seguente:
import java.util.*; public class Esercizio4U { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println("Digita il primo operando e batti enter."); double primoOperando = Double.parseDouble(scanner.nextLine()); System.out.println( "Ora scegli l'operazione da eseguire e batti enter:"); stampaTabellaOperazioni(); String operazione = scanner.nextLine(); System.out.println("Ora scegli il secondo operando e batti enter "); double secondoOperando = Double.parseDouble(scanner.nextLine()); double risultato = eseguiOperazione(primoOperando, secondoOperando, operazione); System.out.println("Risultato = " + risultato); } private static double eseguiOperazione(double primoOperando, double secondoOperando, String operazione) { CalcolatriceSemplificata calcolatriceSemplificata = new CalcolatriceSemplificata(); switch (operazione) { case "+": return calcolatriceSemplificata.somma( primoOperando, secondoOperando); case "-": return calcolatriceSemplificata.sottrai( primoOperando, secondoOperando); case "x": return calcolatriceSemplificata.moltiplica( primoOperando, secondoOperando); case "d": return calcolatriceSemplificata.dividi( primoOperando, secondoOperando); case "r": return calcolatriceSemplificata.restituisciResto( primoOperando, secondoOperando); case "u": return calcolatriceSemplificata.massimo( primoOperando, secondoOperando); case "m": return calcolatriceSemplificata.minimo( primoOperando, secondoOperando); default: System.out.println("Operazione specificata " + operazione + " non valida"); System.exit(1); return Double.NaN; } } private static void stampaTabellaOperazioni() { System.out.println("'+' : somma"); System.out.println("'-' : sottrai"); System.out.println("'x' : moltiplica"); System.out.println("'d' : dividi"); System.out.println("'r' : restituisci resto della divisione"); System.out.println("'u' : massimo"); System.out.println("'m' : minimo"); } }
La traccia dell'esercizio aveva già delineato come implementare l'interazione tra l'utente e il programma. Per il resto il codice è abbastanza chiaro, e faremo giusto delle osservazioni sui punti più oscuri.
Si noti che per eseguire i calcoli abbiamo usato il tipo di dato numerico più largo: ildouble
. Si noti anche l'utilizzo del metodo staticoparseDouble
della classeDouble
, che converte una stringa indouble
(cfr. documentazione ufficiale), così come il metodoparseInt
della classeInteger
converte una stringa inint
(cfr. esercizio 3.t).
Notare però che l’istruzioneNon abbiamo gestito (non era richiesto) l'eventuale scorretto utilizzo del programma da parte dell'utente, perché troppo impegnativo per le nozioni che abbiamo studiato sin qui. Con la gestione delle eccezioni che studieremo nel capitolo 8 invece si troveranno delle soluzioni semplici. Purtroppo il programma in alcune operazioni perde di precisione. Potete verificarlo per esempio eseguendo una operazione di resto dalla divisione traDouble.parseDouble(scanner.nextLine())
che abbiamo usato per ottenere il contenuto dei due operandi potrebbe essere tranquillamente sostituita dalla più semplice istruzionescanner.nextDouble()
. Infatti la classeScanner
definisce metodi per il recupero di tutti i tipi di dati primitivi.2.3
e2
, che dà per risultato un valore non preciso come si può notare da questo esempio di output:
Digita il primo operando e batti enter. 2.3 Ora scegli l'operazione da eseguire e batti enter: '+' : somma '-' : sottrai 'x' : moltiplica 'd' : dividi 'r' : restituisci resto della divisione 'u' : massimo 'm' : minimo Ora scegli il secondo operando e batti enter 2 Risultato = 0.2999999999999998
Questo è dovuto dal modo in cui viene rappresentato il tipo
double
in memoria, e lo avevamo anche accennato nel paragrafo 3.3.2.1 (bisognerebbe utilizzare il tipoBigDecimal
, cfr. documentazione ufficiale), ed è un problema comune a tutti i linguaggi di programmazione moderni che utilizzano lo stesso metodo di rappresentazione in memoria (Standard IEEE-754). Il metodoSystem.exit
fa terminare il programma istantaneamente. C'è da notare inoltre che il programma propone all'utente di scegliere delle lettere specifiche (vedi metodoeseguiOperazione
) per eseguire la scelta dell'operazione da eseguire. -
Esercizio 4.v)
Dichiarare una classe
StranaCalcolatrice
che dato un numero imprecisato di numeri definisca i metodi per:
1. Sommarli.
2. Moltiplicarli.
3. Restituire il numero più grande (il massimo).
4. Restituire il numero più piccolo (il minimo).
Soluzione
La classe
StranaCalcolatrice
potrebbe essere la seguente:public class StranaCalcolatrice { public double somma(double[] doubles) { double risultato = 0; for (double unDouble : doubles) { risultato += unDouble; } return risultato; } public double moltiplica(double[] doubles) { double risultato = doubles[0]; for (int i = 1; i < doubles.length; i++) { risultato *= doubles[i]; } return risultato; } public double massimo(double[] doubles) { double max = doubles[0]; for (int i = 1; i < doubles.length; i++) { double unDouble = doubles[i]; if (unDouble > max) { max = unDouble; } } return max; } public double minimo(double[] doubles) { double min = doubles[0]; for (int i = 1; i < doubles.length; i++) { double unDouble = doubles[i]; if (unDouble < min) { min = unDouble; } } return min; } }
Il metodo
somma
è molto semplice e viene usato un semplice ciclo foreach per eseguire la somma. Negli altri tre casi, abbiamo dovuto prima recuperare il primo elemento, per poi svolgere le operazioni con il resto degli elementi dell'array passato in input.
Mentre la classe di test potrebbe essere la seguente:
public class Esercizio4V { public static void main(String args[]) { StranaCalcolatrice stranaCalcolatrice = new StranaCalcolatrice(); double [] a1 = {42.7, 47.8}; System.out.println("42.7 + 47.8 = " + stranaCalcolatrice.somma(a1)); double [] a2 = {42.7, 47.8, 2}; System.out.println("42.7 x 47.8 x 2= " + stranaCalcolatrice.moltiplica(a2)); double [] a3 = {42.7, 47.8, 50, 2, 8, 89}; System.out.println("Il massimo tra 42.7, 47.8, 50, 2, 8, 89 è " + stranaCalcolatrice.massimo(a3)); double [] a4 = {42.7, 47.8, 50, 2, 8, 89}; System.out.println("Il minimo tra 42.7, 47.8, 50, 2, 8, 89 è " + stranaCalcolatrice.minimo(a4)); */ } }
Tuttavia il dover creare prima degli array per poter invocare questi metodi risulta piuttosto scomodo. C’è una soluzione più funzionale che viene spiegata solo nel paragrafo 7.2.2. Infatti, invece di dichiarare array come parametri dei metodi, possiamo usare dei varargs, ovvero dei parametri che accettano un numero indefinito di elementi. Basta riscrivere i nostri parametri usando un’ellissi (ovvero dei puntini sospensivi “...
”), al posto delle parentesi quadre. In pratica basta riscrivere la classeStranaCalcolatrice
in questo modo:
public class StranaCalcolatrice { public double somma(double... doubles) { double risultato = 0; for (double unDouble : doubles) { risultato += unDouble; } return risultato; } public double moltiplica(double... doubles) { double risultato = doubles[0]; for (int i = 1; i < doubles.length; i++) { risultato *= doubles[i]; } return risultato; } public double massimo(double... doubles) { double max = doubles[0]; for (int i = 1; i < doubles.length; i++) { double unDouble = doubles[i]; if (unDouble > max) { max = unDouble; } } return max; } public double minimo(double... doubles) { double min = doubles[0]; for (int i = 1; i < doubles.length; i++) { double unDouble = doubles[i]; if (unDouble < min) { min = unDouble; } } return min; } }
È possibile notare che il codice dei metodi non è cambiato affatto. Infatti, all’interno del metodo, un varargs è solamente un array che usa una sintassi diversa. Il vantaggio di utilizzare un varargs al posto di un array come parametro di un metodo, è quella che non è necessario creare prima un array per passarlo coma parametro, ma possiamo direttamente passare gli elementi che avremmo dovuto mettere all’interno dell’array. Quindi possiamo riscrivere la classe di test nel seguente modo:
public class Esercizio4V { public static void main(String args[]) { StranaCalcolatrice stranaCalcolatrice = new StranaCalcolatrice(); System.out.println("42.7 + 47.8 = " + stranaCalcolatrice.somma(42.7, 47.8)); System.out.println("42.7 x 47.8 x 2= " + stranaCalcolatrice.moltiplica(42.7, 47.8, 2)); System.out.println("Il massimo tra 42.7, 47.8, 50, 2, 8, 89 è " + stranaCalcolatrice.massimo(42.7, 47.8, 50, 2, 8, 89)); System.out.println("Il minimo tra 42.7, 47.8, 50, 2, 8, 89 è " + stranaCalcolatrice.minimo(42.7, 47.8, 50, 2, 8, 89)); } }
semplificando molto il nostro sforzo implementativo. Per tutti i dettagli potete approfondire il discorso studiando il paragrafo 7.2.2, anche se per ora non è necessario. -
Esercizio 4.w)
Dichiarare una classe che utilizza la classe
Scanner
, che permette all'utente di interagire con la classeStranaCalcolatrice
. Al lettore è lasciata la decisione di come l'utente dovrà interagire con il programma. Il suggerimento è quello di scrivere un algoritmo su un foglio di carta prima di iniziare a scrivere il codice.
Attenzione che i metodi bloccanti diScanner
leggono le pressioni dei tasti. Questo significa che a volte troveremo caratteri non riconosciuti in output, in corrispondenza della pressione di tasti come "Maiuscolo", o "Canc".
Soluzione
Il listato richiesto potrebbe essere il seguente:
import java.util.*; public class Esercizio4Z { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println( "Digita un operando e batti enter, tutte le volte che vuoi." + "\nQuando hai finito scegli l'operazione da eseguire e batti enter."); stampaTabellaOperazioni(); String temp; String operandiString = ""; while (isNotOperation(temp = scanner.nextLine())) { operandiString += temp + "-"; } if (isNotOperation(temp)) { System.out.println("Errore codice operazione"); } String[] operandiArray = operandiString.split("-"); double[] operandi = new double[operandiArray.length]; for (int i = 0; i < operandiArray.length; i++) { operandi[i] = Double.parseDouble(operandiArray[i]); } double risultato = eseguiOperazione(operandi, temp); System.out.println("Risultato = " + risultato); } private static boolean isNotOperation(String line) { if (line.equals("+") || line.equals("x") || line.equals("u") || line.equals("m")) { return false; } return true; } private static double eseguiOperazione(double[] operandi, String operazione) { StranaCalcolatrice stranaCalcolatrice = new StranaCalcolatrice(); switch (operazione) { case "+": return stranaCalcolatrice.somma(operandi); case "x": return stranaCalcolatrice.moltiplica(operandi); case "u": return stranaCalcolatrice.massimo(operandi); case "m": return stranaCalcolatrice.minimo(operandi); default: System.out.println("Operazione specificata " + operazione + " non valida"); System.exit(1); return Double.NaN; } } private static void stampaTabellaOperazioni() { System.out.println("'+' : somma"); System.out.println("'x' : moltiplica"); System.out.println("'u' : massimo"); System.out.println("'m' : minimo"); } }
Abbiamo deciso di far specificare all'utente tutti gli operandi, per poi eseguire l'operazione nel momento in cui viene specificato un possibile operatore. Progettare una soluzione al problema non era affatto banale. Anche in questo caso non abbiamo gestito (non era richiesto) l'eventuale scorretto utilizzo del programma da parte dell'utente, perché troppo impegnativo per le nozioni che abbiamo studiato sin qui. Con la gestione delle eccezioni che studieremo nel capitolo 8 invece si troveranno delle soluzioni semplici. Il punto critico del codice riguarda la gestione dell'input, che deve essere analizzato e trasformato in tipi di dati che servono per compiere le nostre operazioni (
double
). Purtroppo ci manca un argomento molto importante che non abbiamo ancora studiato come le collection (che approfondiremo solo nell'appendice H, ma introdurremo a partire dal capitolo 10). Senza questo argomento, per immagazzinare i vari operandi specificati dall'utente, ci siamo dovuti arrangiare con una stringa (operandiString
) che conteneva i vari operandi separati dal simbolo di trattino. Poi con il metodosplit
(vedi documentazione della classeString
), abbiamo ottenuto un array di operandi sotto forma di stringa (operandiArray
). Poi abbiamo istanziato un array didouble
operandi
della stessa dimensione dioperandiArray
, e lo abbiamo riempito con gli operandi di tipodouble
dopo averli convertiti tramite il metodo staticoparseDouble
della classeDouble
.
Una soluzione piuttosto artificiosa, che però ha funzionato. Ecco un esempio di esecuzione dell'applicazione:
Digita un operando e batti enter, tutte le volte che vuoi. Quando hai finito scegli l'operazione da eseguire e batti enter. '+' : somma 'x' : moltiplica 'u' : massimo 'm' : minimo 2 3 4 5 6 7.28 x Risultato = 5241.6
-
Esercizio 4.x)
Utilizzando la classe
TestaOCroce
definita nella soluzione dell'esercizio 4.l, creare una classe chiamataGiocoTestaOCroce
, che simuli il lancio di una moneta, e che permetta all'utente di indovinare se uscirà "Testa
" o "Croce
". Il programma dovrà stampare un messaggio finale che stabilisca che se l'utente ha vinto (ovvero ha indovinato) oppure no.
Soluzione
Il codice richiesto potrebbe essere il seguente:
import java.util.*; public class GiocoTestaOCroce { public static void main(String args[]) { System.out.println("Cosa scegli testa o croce?"); Scanner scanner = new Scanner(System.in); String scelta = scanner.nextLine(); if ("testa".equals(scelta)) { System.out.println("Ok, lancio..."); TestaOCroce testaOCroce = new TestaOCroce(); String risultatoLancio = testaOCroce.dammiTestaOCroce(); System.out.print("È uscito " + risultatoLancio + "..."); System.out.println("testa".equalsIgnoreCase(risultatoLancio) ? "hai vinto!" : "hai perso!"); } else if ("croce".equals(scelta)) { System.out.println("Ok, lancio..."); TestaOCroce testaOCroce = new TestaOCroce(); String risultatoLancio = testaOCroce.dammiTestaOCroce(); System.out.print("È uscito " + risultatoLancio + "..."); System.out.println("croce".equalsIgnoreCase(risultatoLancio) ? "hai vinto!" : "hai perso!"); } else { System.out.println( "Mi dispiace, puoi scrivere solo testa o croce, riprova..."); System.out.println("Programmata terminato... ciao!"); } } }
L'algoritmo implementato sembra funzionare, purtroppo lo stesso codice è ripetuto più volte. Per ora va bene così perché abbiamo raggiunto il nostro scopo, ma nei prossimi capitoli cercheremo di migliorare la qualità del nostro codice. -
Esercizio 4.y)
Modificare la classe
GiocoTestaOCroce
creato nell'esercizio precedente, in modo tale che il programma inizialmente permetta di specificare il numero di lanci da fare. Il programma dovrà contare il numero di volte che l'utente ha indovinato il risultato del lancio e il numero di volte che non ha indovinato, e dovrà decidere se l'utente ha vinto la partita oppure no.
Soluzione
Il codice richiesto potrebbe essere il seguente:
import java.util.*; public class GiocoTestaOCroce { public static void main(String args[]) { System.out.println( "Giochiamo a testa o croce, quante lanci vuoi fare?"); Scanner scanner = new Scanner(System.in); String numeroLanciString = scanner.nextLine(); int numeroLanci = Integer.parseInt(numeroLanciString); int contatoreLanci = 1; var numeroVittorie = 0; var numeroSconfitte = 0; String messaggio = ""; System.out.println("Hai scelto di fare "+ numeroLanci +"...iniziamo!"); while (contatoreLanci <= numeroLanci) { System.out.println("Lancio numero " + contatoreLanci); System.out.println("Cosa scegli testa o croce?"); String scelta = scanner.nextLine(); if ("testa".equals(scelta)) { System.out.println("Ok, lancio..."); TestaOCroce testaOCroce = new TestaOCroce(); String risultatoLancio = testaOCroce.dammiTestaOCroce(); contatoreLanci++; System.out.print("È uscito "+ risultatoLancio + "..."); if ("testa".equalsIgnoreCase(risultatoLancio)) { messaggio = "hai vinto!"; numeroVittorie++; } else { messaggio = "hai perso!"; numeroSconfitte++; } } else if ("croce".equals(scelta)) { System.out.println("Ok, lancio..."); TestaOCroce testaOCroce = new TestaOCroce(); String risultatoLancio = testaOCroce.dammiTestaOCroce(); contatoreLanci++; System.out.print("È uscito "+ risultatoLancio + "..."); if ("croce".equalsIgnoreCase(risultatoLancio)) { messaggio = "hai vinto!"; numeroVittorie++; } else { messaggio = "hai perso!"; numeroSconfitte++; } } else { messaggio = "Mi dispiace, puoi scrivere solo testa o croce," + " riprova..."; } System.out.println(messaggio); } messaggio = "Hai vinto " + numeroVittorie + " volte, e perso " + numeroSconfitte + " volte, quindi..."; if (numeroVittorie > numeroSconfitte) { messaggio += "hai vinto la partita! Complimenti!"; } else if (numeroVittorie < numeroSconfitte) { messaggio += "hai perso la partita! Ah ah!"; } else { messaggio += "hai pareggiato partita! Riprova!"; } System.out.println(messaggio); } }
Il codice è abbastanza comprensibile, ed il lettore dovrebbe essere in grado di interpretarlo da solo. Notiamo che abbiamo usato il metodo
equalsIgnoreCase
della classeString
per fare i confronti senza tenere conto delle lettere maiuscole e minuscole. Inoltre possiamo notare la gestione della variabilecontatoreLanci
, che viene incrementato solo quando effettivamente il lancio viene eseguito, ma non quando il lancio non viene eseguito nel caso l'input dell'utente non sia compatibile con la logica del programma. -
Esercizio 4.z)
Riprendendo la classe
Rubrica
creata nell'esercizio 3.x, creare un metodo chiamatocercaContattiPerNome(String nome)
che prende come input una stringa che può rappresentare un nome o una parte di esso, e deve restituire un array di oggettiContatto
che contengano la stringa nel proprio nome. Creare anche una classe di test chiamataRicercaContatti
che permette all'utente di specificare la stringa da passare come criterio di ricerca al metodocercaContattiPerNome
e che stampi i risultati della ricerca.
Soluzione
Inseriamo nella classe
Rubrica
il metodo richiesto:
public class Rubrica { public Contatto[] contatti; public Rubrica () { contatti = new Contatto[]{ new Contatto("Claudio De Sio Cesari", "Via Java 13", "131313131313"), new Contatto("Stevie Wonder", "Via Musica 10", "1010101010"), new Contatto("Gennaro Capuozzo", "Piazza Quattro Giornate 1", "1111111111") }; } public Contatto[] cercaContattiPerNome(String nome) { Contatto []contattiTrovati = new Contatto[contatti.length]; for (int i = 0, j = 0; i < contattiTrovati.length; i++) { if (contatti[i].nome.toUpperCase().contains(nome.toUpperCase())) { contattiTrovati[j] = contatti[i]; j++; } } return contattiTrovati; } }
L'algoritmo non è banale, ed usa anche un ciclo
for
che sfrutta due indici (i
ej
), che vengono usati per i due array coinvolti. Notare che l'array restituito (contattiTrovati
) avrà la stessa dimensione dell'array contatti, anche se magari i suoi elementi non saranno inizializzati. Notare anche che prima di usare il metodocontains
della classeString
per controllare se un nome di un contatto contiene la parametro di metodonome
, abbiamo usato il metodotoUpperCase
per fare un confronto che non dipende dalla maiuscole e dalle minuscole. La classeRicercaContatti
richiesta, la potremmo implementare nel seguente modo:
import java.util.Scanner; public class RicercaContatti { public static void main(String args[]) { System.out.println("Ricerca Contatti"); System.out.println(); var rubrica = new Rubrica(); System.out.println("Inserisci nome o parte del nome da ricercare"); Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); Contatto[] contattiTrovati = rubrica.cercaContattiPerNome(input); System.out.println("Contatti trovati con nome contenente \"" + input +"\"" ); for (Contatto contatto : contattiTrovati) { if (contatto != null) { contatto.stampaDettagli(); } } } }
Notare che vengono stampati gli elementi dell'array ritornato, solo se diversi da
null
. -
Esercizio 4.aa) JShell, Vero o Falso:
1. JShell è un programma che si trova nella directory bin del JDK, come i comandi java e javac, e lo possiamo richiamare direttamente da riga di comando, perché abbiamo settato correttamente la variabile
PATH
alla cartella bin a cui appartiene.
2. JShell è un IDE.
3. In una sessione JShell non è possibile dichiarare package.
4. Il simbolo di terminazione di uno statement ; si può omettere solo se scriviamo un'istruzione Java su di un'unica riga.
5. Dichiarare due volte la stessa variabile è possibile, perché JShell segue regole diverse rispetto al compilatore. L'ultima variabile dichiarata sovrascriverà la precedente.
6. Se dichiariamo una variabile di tipoString
senza inizializzarla, essa sarà inizializzata automaticamente anull
.
7. Non è possibile dichiarare un'interfaccia in una sessione JShell.
8. Il modificatoreabstract
è sempre ignorato all'interno di una sessione JShell.
9. Non è possibile dichiarare un metodomain
in una sessione JShell.
10. È possibile dichiarare annotazioni ed enumerazioni in una sessione JShell.
Soluzione
1. Vero.
2. Falso.
3. Vero.
4. Vero.
5. Vero.
6. Vero, le variabili non inizializzate vengono inizializzate ai propri valori nulli. Una stringa, essendo un oggetto, ha come valore nullo proprionull
.
7. Falso.
8. Falso.
9. Falso, è possibile dichiarare un metodomain
, ma non avrà lo stesso ruolo di "metodo iniziale" come in un ordinario programma Java.
10. Vero. -
Esercizio 4.bb) JShell comandi, Vero o Falso:
1. Per terminare una sessione JShell, bisogna digitare il comando
goodbye
.
2. Tutti i comandi di JShell devono avere come prefisso il simbolo\
.
3. I comandihelp
e?
sono equivalenti.
4. Il comandohistory
mostra tutti gli snippet e tutti i comandi lanciati dall'utente nella sessione corrente. Accanto agli snippet è presente uno snippet id che permette di richiamare lo snippet corrispondente.
5. Il comandolist
mostra tutti i comandi digitati dall'utente in questa sessione.
6. Se lanciamo il comando/types -all
elencherà tutte le variabili dichiarate nella sessione corrente.
7. Il comandoreload
provocherà che tutte le istruzioni eseguite nella sessione corrente siano eseguite nuovamente.
8. Il comandodrop
può cancellare un certo snippet specificando il suo snippet id.
9. Se specifichiamo il comando/set start JAVASE
, importeremo in questa ed in tutte le altre sessioni future di JShell, tutte i package di Java Standard Edition.
10. Con li comando/!
richiamiamo l'ultimo snippet editato, sia esso valido o non valido.
Soluzione
1. Falso, bisogna digitare il comando
exit
.
2. Falso, tutti i comandi JShell devono avere come prefisso/
.
3. Vero.
4. Falso, è vero che il comandohistory
mostra tutti gli snippet e tutti i comandi lanciati dall'utente nella sessione corrente. Ma non è vero che accanto agli snippet è presente uno snippet id.
5. Falso, il comandolist
mostra tutti gli snippet digitati dall'utente in questa sessione, con accanto i rispettivi snippet id.
6. False, il comando/types -all
elencherà tutte i tipi (classi, interfacce, enumerazioni, annotazioni) dichiarate nella sessione corrente. Piuttosto il comando/variables -all
elencherà tutte le variabili dichiarate nella sessione corrente.
7. Vero.
8. Vero.
9. Falso, è vero che importeremo in questa sessione, tutte i package di Java Standard Edition, ma non nelle future sessioni (avremmo dovuto esplicitare anche l'opzione-retain
).
10. Vero. -
Esercizio 4.cc)
Consideriamo le seguenti righe editate all'interno di una sessione JShell:
jshell> public int a; a ==> 0 jshell> private String a a ==> null jshell> /reset | Resetting state. jshell> /list
Soluzione
L'output del comando
list
sarà vuoto. Infatti il comandoreset
avrà resettati tutti gli snippet immessi. -
Esercizio 4.dd)
Considerando tutte le istruzioni del precedente esercizio, quale sarà l'output del seguente comando?
jshell> /history
Soluzione
L'output del comando
history
sarà il seguente:
public int a; private String a /reset /list /history
-
Esercizio 4.ee)
Se volessimo aprire il file HelloWorld.java (realizzato nel primo capitolo) all'interno di JShell che si trova nella cartella corrente, che comando dobbiamo lanciare?
1./save HelloWorld.java
2./retain HelloWorld.java
3./reload HelloWorld.java
4./open HelloWorld.java
5./start HelloWorld.java
6./env HelloWorld.java
7./!
Soluzione
Il comando corretto è:
/open HelloWorld.java
-
Esercizio 4.ff)
Una volta aperto il file HelloWorld.java all'interno di una sessione JShell, come possiamo far stampare la stringa
Hello World!
?
Soluzione
Possiamo solo invocare il metodo
main
nel seguente modo:jshell> HelloWorld hw = new HelloWorld(); hw ==> HelloWorld@52a86356 jshell> hw.main(null); Hello World!
Notare che siccome l'array
args
non viene utilizzato all'interno del metodomain
, allora abbiamo potuto passarglinull
.
Anche se non l'abbiamo ancora studiato seriamente, il modificatorestatic
ci permette di evitare di istanziare l'oggettohw
, e lanciare direttamente il comando usando il nome della classe:
jshell> HelloWorld.main(null) Hello World!
-
Esercizio 4.gg)
Che comando dobbiamo lanciare se vogliamo copiare il file HelloWorld.java aperto nell'esercizio 4.ee in una cartella C:/cartella?
1.
/save HelloWorld.java
2./retain HelloWorld.java
3./save HelloWorld2.java
4./save C:/cartella/HelloWorld.java
5./save -start start C:/cartella/HelloWorld.java
6./env C:/cartella/HelloWorld.java
7./! C:/cartella/HelloWorld.java
Soluzione
Il comando corretto è:
/save C:/cartella/HelloWorld.java
-
Esercizio 4.hh) JShell strumenti ausiliari, Vero o Falso:
1. In una sessione JShell è possibile dichiarare una variabile senza specificare un reference.
2. In una sessione JShell è possibile dichiarare un reference senza specificare il tipo del reference.
3. In una sessione JShell è possibile scrivere un valore, poi con il tasto "TAB" far dedurre automaticamente il tipo della variabile a JShell, per poi scrivere il nome del reference.
4. Mentre si dichiara un reference ad un tipo non importato, è possibile farci suggerire da JShell una lista di possibiliimport
da usare per il tipo, premendo contemporaneamente i tasti "SHIFT" e "TAB", rilasciarli e dopo premere il tasto "v".
5. Ilcomando /edit
aprirà il programma Notepad++.
6. In una sessione JShell la pressione contemporanea dei tasti "CTRL – BARRA SPAZIATRICE" provoca l'auto-completamento del codice che si è iniziato a scrivere, o nel caso di più opzioni disponibili, la scelta tra esse.
7. In una sessione JShell la pressione contemporanea dei tasti "CTRL – E" provoca lo spostamento del cursore al termine della riga.
8. In una sessione JShell la pressione contemporanea dei tasti "ALT – D" provoca la cancellazione della parola alla destra del cursore.
9. Il comando/set
feedback silent provoca che JShell eviti di stampare i messaggi dell'analisi del codice scritto.
10. ScrivendoSystem
e premendo due volte il tasto "TAB", JShell ci mostrerà la documentazione della classeSystem
.
Soluzione
1. Vero, in questo caso si parla di variabile implicita, e JShell ne dedurrà automaticamente il tipo.
2. Vero, in questo caso si parla di forwarding reference, e JShell creerà il reference, ma non lo renderà disponibile sino a quando non dichiareremo anche il suo tipo. A quel punto il reference verrà sostituito e inizializzato anull
.
3. Falso, bisogna invece premere contemporaneamente i tasti "SHIFT e TAB", rilasciarli e dopo premere il tasto "v" (che sta per "variable"). JShell dedurrà il tipo della variabile, la dichiarerà e posizionerà il cursore subito dopo per permetterci di definire il reference.
4. Falso, bisogna invece premere contemporaneamente i tasti "SHIFT e TAB", rilasciarli e dopo premere il tasto "i" (che sta per "input").
5. Falso, verrà aperto il programma JShell Edit Pad, a meno che prima non si sia impostato come editor di default Notepad++ mediante il comando:6. Falso, la pressione del tasto "TAB" provoca l'auto-completamento del codice che si è iniziato a scrivere, o nel caso di più opzioni disponibili, la scelta tra esse./set editor C:\Program Files (x86)\Notepad++\notepad++.exe
7. Vero.
8. Vero.
9. Vero.
10. Vero. -
Esercizio 4.ii)
Sfruttano la proprietà dei tipi
char
di essere compatibili con il tipo intero, scrivere una classe con il metodomain
, che sfruttando un ciclofor
, inizializzi la seguente variabile:
char alfabeto [] = new char[26];
I caratteri dell'alfabeto sono 26 e non 21 perché contiamo anche i caratteri j, k, w, x e y.
Soluzione
Il codice richiesto potrebbe essere il seguente:
public class AlfabetoArray { public static void main(String args[]) { char alfabeto [] = new char[26]; int i = 0; for (char c = 'a'; c <= 'z'; c++, i++) { alfabeto[i] = (char)c; } System.out.println(alfabeto); } }
-
Esercizio 4.jj)
Considerato la soluzione dell'esercizio 4.jj, aggiungere il ciclo più semplice che stampa tutti gli elementi dell'array alfabeto.
Soluzione
Meglio usare un ciclo
for
migliorato:
public class AlfabetoArray { public static void main(String args[]) { char alfabeto [] = new char[26]; int i = 0; for (char c = 'a'; c <= 'z'; c++, i++) { alfabeto[i] = (char)c; } for (char lettera : alfabeto) { System.out.println(lettera); } } }