9. Input dell’utente: la classe Scanner
Andrea Pastore 19/03/2020 0
I programmi che abbiamo visto finora non prevedono l’interazione da parte dell’utente, possono solo essere avviati. Questo è diverso dai programmi reali, che danno la possibilità all’utente di interagire. Cominciamo a vedere la forma più semplice di interazione dell’utente, con dei programmi che saranno in grado di prendere input da tastiera.
Per questo utilizzeremo la classe Scanner, una delle tante classi messe a disposzione da Java per degli scopi specifici. Nel caso della classe Scanner questa è stata creata per consentire a Java di prendere in input dati testuali o numerici. Facciamo un esempio: il codice qui sotto chiede all’utente di scrivere qualcosa con la tastiera e poi stamperà quello che l’utente ha scritto.
import java.util.Scanner;
public class HelloScanner {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Scrivi qualcosa");
String s = input.nextLine();
System.out.println("Hai scritto: "+s);
}
}
Notiamo che questo programma ha una nuova riga di codice:
import java.util.Scanner;
Quando vogliamo usare una classe messa a disposizione da Java dobbiamo importarla. Faremo la stessa cosa in seguito quando importeremo classi realizzate da noi. Continuiamo l’analisi del nostro programma: vediamo subito dopo una classe e poi un metodo main, che sono cose a noi note. Poi vediamo un’altra riga di codice nuova:
Scanner input = new Scanner(System.in);
con questa riga stiamo creando un oggetto di tipo Scanner. Questa cosa ci sarà più chiara in seguito, per ora prendiamolo come un passaggio necessario per prendere in input questi dati. Proseguendo la lettura del codice troviamo un altro comando a noi noto, quello che ordina a Java di stampare:
System.out.println("Scrivi qualcosa");
Seguito da :
String s = input.nextLine();
che consente a java di recuperare il testo inserito dall’utente. In sostanza Il programma chiede all’utente di scrivere qualcosa (con il comando precedente) e poi si mette in ascolto: resterà bloccato fino a quando l’utente non avrà scritto qualcosa e premuto invio.
La riga successiva che troviamo
System.out.println("Hai scritto: "+s);
stampa a video ciò che ha scritto l’utente.
Recuperare tipi di dati diversi da String
Per la maggior parte del tempo utilizzeremo lo scanner per recuperare stringhe, ma può capitarci di dover recuperare altri tipi di dati ad esempio numeri interi o decimali. In questo caso dovremmo usare il seguente codice:
int n = input.nextInt(); // recuperiamo un numero intero
double d = input.nextDouble(); // recuperiamo un numero decimale
Nota: questi metodi possono creare dei problemi se subito dopo aver recuperato una numero dobbiamo recuperare una stringa. Se si verifica questa esigenza dobbiamo recuperare una stringa e poi fare la conversione, come mostrato in seguito:
System.out.println("Scrivi un numero");
String s = input.nextLine();
int n = Integer.parseInt(n);
Potrebbero interessarti anche...
Andrea Pastore 19/03/2020
12. Polimorfismo in Java
Alcuni linguaggi di programmazione consentono di decidere il comportamento dei metodi e costruttori in base al numero di variabili che vengono passate loro come parametro. Supponiamo ad esempio di avere una classe Java chiamata Utente, con tre variabili (id, nome, cognome) e due costruttori: il primo prenderà in input solo una variabile id, il secondo prenderà in input una variabile id, una variabile nome e una variabile cognome.
I due costruttori in java saranno i seguenti
public Utente(int id) {
this.id = id;
this.nome = “”;
this.cognome = “”;
this.email = “”;
}
public Utente(int id, String nome, String cognome) {
this.id = id;
this.nome = nome;
this.cognome = cognome;
}
Quando noi invochiamo il costruttore a seconda del numero di parametri che inseriamo Java userà il costruttore che combacia con i parametri inseriti ed eseguirà il codice contenuto all’interno. Java darà un errore solo se non trova un costruttore con il numeor di parametri da noi specificato. Ad esempio se scriviamo:
Utente utente = new Utente(3,”Mario”,”Rossi”,”mario@gmail.com”);
Otterremo un errore, perché non abbiamo definito un costruttore che prende in input quattro parametri. Tutto quello che abbiamo detto per i costruttori è valido anche per i metodi (del resto il costruttore non è altro che un metodo speciale). Prendiamo in esame il seguente metodo che stampa tutti i dati dell’utente:
public void stampaDati() {
System.out.println(this.id + “ ” + this.nome + “ ” + this.cognome + “ ” +this.email);
}
Come per i costruttori possiamo creare un altro metodo che ha lo stesso nome, ma prende in input un parametro per stabilire come devono essere stampati questi elementi. Stabiliamo due tipologie di stampa: essenziale che stampa solo nome e cognome, completa che stampa tutto. Se il parametro passato in input non corrisponde a nessuna di queste due cose allora questo metodo invoca a sua volta il metodo stampaDati senza parametri, che stamperà i dati senza formattazione.
public void stampaDati(String tipoVisualizzazione) {
if(tipoVisualizzazione.equals("essenziale")) {
System.out.println("Nome:"+this.nome+"; Cognome:"+this.cognome);
}
else if (tipoVisualizzazione.equals("completa")){
System.out.println("Id: "+this.id + "; Nome:"+this.nome+"; Cognome:"+this.cognome+"; Email:"+this.email);
}
else {
stampaDati();
}
}
Ereditarietà
L’ereditarietà è una caratteristica di molti linguaggi di programmazione moderni che consente di ottimizzare il codice scritto ed evitare ripetizioni. Ci sono casi in cui dobbiamo creare classi molto simili tra loro. Per questo molti linguaggi di programmazione consentono di usare il meccanismo dell’ereditarietà. Supponiamo di avere bisogno di questa due classi:
- Utente
id, nome, cognome, email,telefono - Fornitore
id, nome, cognome, email,telefono,partitaIva
notiamo che Fornitore è quasi uguale alla classe Utente, quindi non ha senso riscriverla. Quando creiamo la classe Fornitore che estenderà la classe Utente. Scriviamo le due classi per renderci conto del codice e delle differenze tra le due. Qui sotto vediamo la classe utente:
public class Utente {
private int id ;
private String nome;
private String cognome;
private String email;
private String telefono;
public Utente(int id, String nome, String cognome, String email, String telefono) {
this.id = id;
this.nome = nome;
this.cognome = cognome;
this.email = email;
this.telefono = telefono;
}
// Getter & setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
… tutti gli altri getter e setter
}
Vediamo ora la classe Fornitore. Come abbiamo capito Java ci consente di evitare di ricopiare la classe, basta dichiarare, al momento della creazione, che la nuova classe estende la classe Utente. Questo avviene con la parola chiave extends.
public class Fornitore extends Utente {
private String partitaIva;
public Fornitore(String partitaIva, int id, String nome, String cognome, String email, String telefono) {
super(id, nome, cognome, email, telefono, via, citta, cap);
this.partitaIva = partitaIva;
}
public String getPartitaIva() {
return partitaIva;
}
public void setPartitaIva(String partitaIva) {
this.partitaIva = partitaIva;
}
}
Notiamo alcune differenze con la classe Utente scritta sopra: innanzitutto vediamo che nel costruttore c’è la parola chiave super, seguita da una serie di parametri. Si tratta dei parametri del costruttore della classe Utente, che viene richiamato con il comando super. Ogni volta che noi estendiamo una classe il costruttore della nuova classe deve richiamare il costruttore della classe che estende. Fornitore estende la classe Utente, quindi il suo costruttore prende in input anche i parametri che richiede il costruttore di Utente, che invocherà con il metodo super().
Nota: quando una classe estende un’altra classe, la classe estesa è definita superclasse
Le interfacce in Java
Vediamo ora un altro concetto fondamentale della programmazione: le interfacce, che servono per standardizzare il codice.
Interfacce
Le interfacce vengono utilizzate per definire un tipo di dato e una classe, che però non viene implementato. Vengono definite solo le firme dei metodi che poi saranno implementate in altre classi. Vediamo un esempio di interfaccia:
public interface Libro {
public void stampaLibro();
public void setTitolo(String titolo);
public String getTitolo();
public void setNumeroPagine(int numeroPagine);
public int getNumeroPagine();
}
Per usare una determinata interfaccia dopo il nome della classe dobbiamo usare la parola chiave implements seguita dal nome dell'interfaccia. Appena facciamo questo il nostro ide ci segnalerà che i metodi dell'interfaccia non sono ancora implementati, clicchiamo su add unimplementated methods (potrebbe cambiare a seconda dell’ide usato) e il nostro ide li aggiungerà per noi, dobbiamo solo completarli con il codice all'interno.
In sostanza le interfacce consentono di standardizzare il codice: dueprogrammatori si accordano sui metodi e su come vengono chiamati, e poiai fini dell'interoperabilità delle classi non è importante come vieneimplementato. Nel tempo le implementazioni possono cambiare, ma rispettandole interfacce non ci saranno problemi di incompatibilità
Il paradigma MVC
La programmazione ad oggetti è utilizzata nel paradigma MVC (MODEL, VIEW, CONTROLLER), che consente una separazione delle logiche. Vediamo i tre elementi nel dettaglio:
- model
sono le classi cosi come le abbiamo viste. Quando creiamo una classe infatti definiamo degli oggetti ma non li usiamo in quell’istante - view
le viste rappresentano la parte del progetto che mostra i dati visivamente - controller
sono i file che consentono di rendere permanenti le operazioni sugli oggetti: creazione di nuovi elementi, modifica di elementi esistenti, eliminazione di elementi e anche recupero dei dati di un elemento. I controller nascondono le logiche sottostanti alle altre classi: potremmo voler salvare i dati in un file oppure nel database, per le classi esterne viene chiamato lo stesso metodo. Facendo passare tutte le operazioni di salvataggio, modifica, caricamento per il controller avremo solo una classe che gestisce queste operazioni, che si traduce in un vantaggio per la manutenibilità del codice, in quanto per apportare modifiche alla gestione degli oggetti dovremmo modificare solo la classe relativa.
Andrea Pastore 19/03/2020
1. Le origini di Java e le sue caratteristiche
Java è un linguaggio di programmazione ad oggetti tra i più comuni al mondo, utilizzato praticamente in tutti i tipi di dispositivi, dai computer ai telefoni, distributori automatici e molto altro. Fu creato da Sun Microsystem nel 1995 ed è poi passato ad Oracle quando quest’ultima ha acquisito Sun.
La macchina virtuale Java
Una caratteristica di Java è quella di girare su tutti i sistemi operativi, senza che il codice venga ricompilato come avviene in altri linguaggi. Questa possibilità ci è data dalla Java Virtual Machine, che si occupa di leggere il codice Java tradurlo nel linguaggio macchina del dispositivo dove si trova.
Organizzazione del codice
Il codice Java è organizzato in classi, che sono contenute in package. Per ora ci basti sapere che una classe è un file contenente codice Java, può richiamare altre classi per fare compiti specifici. Le classi a loro volta sono suddivise in metodi, che possono essere richiamati dalla stessa classe o da altre classi.
Un programma java può avere un numero variabile di classi che può essere anche molto elevato (si pensi per esempio a programmi come Eclipse). Un programma Java deve avere sempre una classe che viene chiamata quando il programma va in esecuzione. Questa classe è chiamata classe main, capiremo più avanti questo concetto.
Un package è una cartella che contiene le classi Java. I progetti java possono essere molto vasti, quindi è necessario ordinare le classi in modo da essere consultabili. Ad esempio supponiamo di avere un programma di una biblioteca, un package potrebbe contenere tutte le classi Java deputate al salvataggio dei dati e un altro potrebbe contenere tutte le classi deputate alla gestione dell’interfaccia grafica.
Commenti
I commenti sono delle stringhe di testo che vegono utilizzate per spiegare il codice che si sta scrivendo. Quando scriviamo un programma non è detto che lo utilizzeremo solo noi, può darsi che quel codice vada in mano ad un collega. È bene quindi commentarlo per far capire a chi legge il codice (anche a noi stessi, se lo rileggiamo dopo un po’ di tempo!) cosa abbiamo fatto.I commenti in java si fanno in due modi:
// commento su singola riga
/*
* commento su più righe
* lo utilizziamo quando dobbiamo spiegare qualcosa di più elaborato
*/
Andrea Pastore 19/03/2020
8. Iterazioni
Tutti i linguaggi di programmazione mettono a disposizione degli strumenti per non scrivere lo stesso comando. Supponiamo di avere questo codice:
System.out.println("Elemento 1");
System.out.println("Elemento 2");
System.out.println("Elemento 3");
System.out.println("Elemento 4");
System.out.println("Elemento 5");
Ovviamente questo codice funziona e stamperà a video queste stringhe, ma si tratta di un codice che occupa molto spazio, senza contare che un domani potremmo voler stampare qualcosa di diverso dalla parola “Elemento”, e dovremmo modificare ogni singola riga di codice. Vediamo due costrutti che possono aiutarci a scrivere meno codice.
Il ciclo for
Il ciclo for consente di eseguire ripetutamente il codice all’interno delle parentesi graffe che lo delimitano. Supponiamo di voler ottenere lo stesso risultato del codice visto ad inizio pagina, ovvero la stampa di cinque righe con Elemento dall’ 1 al 5. Otterremmo lo stesso risultato scrivendo questo codice:
for(int i =1;i<6;i++) {
System.out.println("Elemento "+i);
}
Il ciclo for per funzionare ha bisogno di tre informazioni, separate dal punto e virgola, da inserire nelle parentesi tonde:
• Variabile contatore e il suo valore di partenza
è la variabile su cui viene eseguito il ciclo, serve per contare le iterazioni in corso. nell’esempio qui sopra è rappresentata dal codice: int i =1. Notiamo che in questo caso la variabile è inizializzata nel ciclo for, potrebbe anche essere stata inizializzata all’esterno e quindi potremmo scrivere solo: i =1.
• valore massimo che deve raggiungere questa variabile
serve per stabilire quando il nostro ciclo for deve fermarsi, viene inserita nel ciclo for subito dopo il contatore. Nel nostro esempio è i<6
• tipo di incremento
server per stabilire di quanto deve essere incrementata la variabile contatore nel ciclo for. Tipicamente viene usato i++ che indica che la variabile viene incrementata ogni volta di 1 alla fine di ogni iterazione. possono comunque essere usati altri valori, ad esempio i = i+2 che invece indica di incrementare la variabile di 2 al termine di ogni iterazione. Gli incrementi non devono per forza essere positivi, possono essere anche negativi: posso usare ad esempio i-- oppure i = i-2
Il ciclo while
Ci sono casi in cui non sappiamo quando possiamo smettere di effettuare un ciclo, perché ad esempio dipende da una condizione esterna al nostro programma. In questi casi non possiamo usare un ciclo for, perché come abbiamo visto l’utilizzo di quest’ultimo prevede che indichiamo con esattezza quante volte deve essere eseguito. Il ciclo while è stato pensato invece per tutti quei casi in cui non sappiamo quante volte dobbiamo eseguire una determinata azione: prende in input solo una condizione, che è quella la discriminante per eseguire ancora o terminare il ciclo while. Ad esempio:
while(test>0) {
System.out.println(test);
test--;
}
In questo caso Java eseguirà il codice contenuto in questo costrutto fino a quando la variabile test è maggiore di 0. Notiamo una cosa: tra i codici di questo costrutto c’è la riga test-- che decrementa di 1 ogni volta. Questo farà si che prima o poi la variabile diventerà uguale a zero e quindi il ciclo while terminerà la sua esecuzione. Nei cicli while bisogna fare attenzione al ciclo infinito: nel caso dell’esempio di sopra se non ci fosse il comando test-- il while eseguirebbe all’infinito il codice al suo interno.
Come nel costrutto if, nel while possiamo scrivere le stesse condizoni usando gli operatori. Ad esempio potremmo scrivere un while che esegue un certo codice fino a quando un determinato numero è diverso da 10:
while(test!=10) {
System.out.println(test);
test++;
}
While e stringhe
Può capitarci di dover fare dei controlli non sui numeri, ma sulle stringhe: il while qui sotto esegue il codice al suo interno fino a quando la stringa in input ha un valore diverso da “uscita”:
while(!str.equals("test")) {
System.out.println(str);
i++;
if(i==15) {
str="test";
}
}
Nota bene: in questo esempio c’è un if che serve per evitare un ciclo infinito. Senza l’if avremo questo codice:
while(!str.equals("test")) {
System.out.println(str);
}
che però genera un ciclo infinito in quanto non ci sono strumenti di controllo che consentono di modificare il valore della variabile str.