OBIETTIVI DELLA LEZIONE
In questa lezione in laboratorio vedremo alcuni dettagli di Java che non avevamo ancora affrontato. Inoltre completeremo e discuteremo eventuali esercizi rimasti irrisolti dalle scorse esercitazioni.
Abbiamo spesso invocato un metodo nel corpo di un altro metodo (ad esempio, lo abbiamo fatto all'interno del corpo del metodo main). È possibile invece che un metodo chiami se stesso?
Quando una funzione chiama se stessa, implicitamente o esplicitamente, la funzione è detta ricorsiva. Il concetto non è solo legato alla programmazione. Anche in matematica esistono funzioni che vengono definite in maniera ricorsiva. Ad esempio il fattoriale di un numero può essere definito ricorsivamente come:
Come calcolo il fattoriale di 2? 2! = 2 × 1! e 1! = 1 × 0! = 1 × 1. La stessa idea può essere applicata ad un qualunque numero n. Java permette di scrivere metodi ricorsivi. Implementiamo lo stesso calcolo in un programma Java.
import javax.swing.*; class CalcolaFattoriale { public static void main (String[] args) { String stringaInput; int numero; stringaInput = JOptionPane.showInputDialog("Inserisci n"); numero = Integer.parseInt(stringaInput); JOptionPane.showMessageDialog(null, "n! è " + fattoriale(numero)); System.exit(0); } public static int fattoriale(int n) { if(n == 0) return 1; else return n*fattoriale(n-1); } }
Ciò che si ottiene con un metodo ricorsivo lo si può ottenere con un ciclo. Vediamo ad esempio come potrebbe essere riscritto il metodo fattoriale().
public static int fattoriale(int n) { int f=1; for(int i=1; i<=n; i++) f*=i; return f; }
La ricorsione porta spesso a scrivere codice più efficace ed elegante ma:
Tutte le volte che abbiamo dichiarato un metodo main(), lo abbiamo sempre fatto con la sintassi:
public static void main (String[] args) ...
Cosa è args? args è un array di oggetti String che vengono eventualemente popolati dalla JVM prima dell'invocazione del metodo main(). Il valore che essi contengono viene specificato dall'utente quando invoca la class. Ad esempio se la classe miaClasse viene invocata con
java miaClasse arg0 arg1 arg2
args verrà inizializzato ad un array di 3 stringhe contenenti rispettivamente "arg0", "arg1" e "arg2". Il valore delle tre stringhe potrà essere utilizzato all'interno del nostro programa per modificarne il funzionamento. L'array args esiste comunque anche se l'utente non fornisce alcun parametro sulla linea di comando; nel tal caso args.length sarà uguale a 0. Per definizione le stringhe sulla linea di comando sono intervallate da spazi. Se volete inserire il parametro "arg 0" (notate lo spazio) dovete "proteggerlo" utilizzando le virgolette doppie:
java miaClasse "arg 0" arg1 arg2
Abbiamo visto come scrivere informazioni su files. Ma come farlo in codifiche diverse da quelle standard? Vediamo in un esempio come scrivere un file con codifica UTF-8 invece della codifica di default di sistema ("Cp1252" in Windows XP).
import java.io.*; class SanMartinoMaiuscolo_UTF8 { public static void main (String[] args) throws IOException { File filePoesiaIn = new File("sanmartino.txt"); File filePoesiaOut = new File("sanmartinomaiuscolo.txt"); FileReader streamPoesiaIn = new FileReader(filePoesiaIn); // Dobbiamo utilizzare uno stream differente da FileWriter! // Per prima cosa dobbiamo creare uno stream binario FileOutputStream // Quindi, dobbiamo incartare lo stream binario in uno testuale che utilizzi la // codifica opportuna: OutputStreamWriter streamPoesiaOut = new OutputStreamWriter(new FileOutputStream(filePoesiaOut), "UTF-8"); // Per verificare il tipo di codifica che stiamo utilizzando System.out.println(streamPoesiaOut.getEncoding()); int carattereLetto; char carattereDaScrivere; while( (carattereLetto=streamPoesiaIn.read()) != -1 ) { carattereDaScrivere = Character.toUpperCase((char)carattereLetto); streamPoesiaOut.write(carattereDaScrivere); } streamPoesiaIn.close(); streamPoesiaOut.close(); } }
©2006 Roberto Sassi