Il metodo main di Java
Cosa significa public static void main(String[] args), perché ogni modificatore è obbligatorio e come vengono passati gli argomenti da riga di comando.
Ogni applicazione Java nasce all'interno di un metodo con una firma molto specifica: public static void main(String[] args). La JVM cerca quella firma, la chiama una volta sola e il programma esegue finché quella chiamata non ritorna (o finché il programma non viene interrotto). Se una qualsiasi parte della firma è sbagliata, la JVM si rifiuta di avviare il programma.
Hai scritto questa riga in ogni esempio fin da Hello World. Questo capitolo la analizza parola per parola, in modo che tu sappia cosa fa ciascuna e quale flessibilità hai.
La firma, parola per parola
public static void main(String[] args) { ... }public— la JVM è "esterna" alla tua classe. Per chiamaremaindall'esterno, deve essere public. Con una visibilità più restrittiva (private, package-private), la JVM non riesce a raggiungerla.static— la JVM non costruisce prima un'istanza della tua classe; chiamamainsulla classe stessa. Quindimaindeve appartenere alla classe, il che è appunto il significato distatic.void—mainnon restituisce nulla. Il codice di uscita di un programma Java non è un valore di ritorno; viene impostato conSystem.exit(...)o vale0di default se il programma termina correttamente.main— il nome letterale che la JVM cerca. ScriverloMain,miano qualsiasi altra cosa fa fallire la JVM conError: Main method not found in class ....String[] args— un singolo parametro, un array di stringhe, che contiene gli argomenti da riga di comando. Il nome del parametro non ha importanza (args,argv,cmdline), conta solo il tipo.
L'array del parametro può anche essere scritto come varargs — String... args — che è lo stesso tipo per la JVM e si comporta in modo identico:
public static void main(String... args) { ... }Entrambe le forme funzionano. La maggior parte del codice usa String[] args per convenzione.
Argomenti da riga di comando
Quando esegui un programma Java dal terminale, tutto ciò che segue il nome della classe diventa un elemento dell'array args:
$ java Greet Ada LovelaceAll'interno di Greet.main, args è {"Ada", "Lovelace"}:
public class Greet {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Hello, stranger");
} else {
System.out.println("Hello, " + String.join(" ", args));
}
}
}args.lengthè il numero di argomenti —0se non ne sono stati forniti.- Ogni elemento è sempre una
String. Per usare un argomento numerico come numero, bisogna convertirlo:int n = Integer.parseInt(args[0]);. - Le virgolette raggruppano gli spazi nella shell —
java Foo "hello world"mette un unico elemento"hello world"inargs.
Cosa non è consentito
La firma è fissa; piccole deviazioni compilano correttamente ma falliscono al lancio — la JVM stampa un Error: ed esce prima che venga eseguito qualsiasi codice:
public void main(String[] args)— mancastatic.Error: Main method is not static in class ....void main(String[] args)— mancanopublic static. Stesso errore "not static".public static int main(String[] args)— tipo di ritornoint.Error: Main method must return a value of type void in class ....public static void Main(String[] args)—Mmaiuscola, o qualsiasi altro nome.Error: Main method not found in class ....public static void main(String args)— tipo del parametro sbagliato (una singolaString, non un array).Error: Main method not found in class ....
Da notare che questi sono errori a runtime, non errori di compilazione — javac li accetta tutti. Il controllo avviene quando java tenta di trovare un punto di ingresso.
Ciò che è consentito e non causa problemi:
finalsul parametro o sul metodo:public static final void main(final String[] args).- Clausole throws:
public static void main(String[] args) throws Exception. A volte comodo per esperimenti rapidi. - Forma vararg:
public static void main(String... args).
Più classi, un solo main
Ogni classe pubblica di primo livello può avere il proprio main. Quando esegui java SomeClass, la JVM cerca main in quella classe. Quindi un progetto di grandi dimensioni può avere decine di classi che portano tutte un main per i test o per punti di ingresso separati; solo quello che nomini nella riga di comando è il punto di ingresso di quella esecuzione.
// File Greet.java
public class Greet {
public static void main(String[] args) { System.out.println("greet"); }
}
// File Sum.java
public class Sum {
public static void main(String[] args) {
int total = 0;
for (String s : args) total += Integer.parseInt(s);
System.out.println(total);
}
}java Greet esegue il primo; java Sum 1 2 3 esegue il secondo e stampa 6.
Uscire da un programma Java
Il ritorno normale di main termina il programma con codice di uscita 0. Per uscire in anticipo, o per impostare un codice di uscita diverso da zero (che segnala un errore a chi ha avviato il programma), si usa System.exit:
if (args.length == 0) {
System.err.println("usage: Sum <number>...");
System.exit(1);
}System.exit non ritorna — ferma la JVM. Usalo con parsimonia; nelle librerie è quasi mai la scelta giusta. In un piccolo programma da riga di comando è il modo standard per segnalare "non sono riuscito a fare il mio lavoro."
Un esempio pratico
Cosa viene dopo
Questo chiude la parte sui metodi: sai scrivere metodi, passare parametri, sovraccaricarli, usare la ricorsione, variare il numero di argomenti e ospitare il punto di ingresso che guida l'intero programma. La parte successiva introduce il contenitore più grande in cui vivono i metodi — classi e oggetti — e il primo assaggio del modello orientato agli oggetti di Java.