4.7 Der Einstiegspunkt für das Laufzeitsystem: main(…)
In Java-Klassen gibt es eine besondere statische Methode main(…), die das Laufzeitsystem in der angegebenen Hauptklasse (oder Startklasse) des Programms aufruft.
4.7.1 Korrekte Deklaration der Startmethode
Damit die JVM ein Java-Programm starten kann, muss es eine besondere Methode main(…) geben. Da die Groß-/Kleinschreibung in Java relevant ist, muss diese Methode main lauten – nicht Main oder MAIN. Die Sichtbarkeit ist auf public gesetzt, und die Methode muss statisch sein, da die JVM die Methode auch ohne ein Exemplar der Klasse aufrufen möchte. Als Parameter wird ein Array von String-Objekten angenommen. Darin sind die auf der Kommandozeile übergebenen Parameter abgelegt.
Zwei Varianten gibt es zur Deklaration:
public static void main( String[] args )
public static void main( String... args )
Die zweite Schreibweise nutzt variable Argumentlisten, ist aber nur eine etwas andere Schreibweise für die Annahme eines Arrays.
Falsche Deklarationen
Nur eine Methode mit dem Kopf public static void main(String[] args) wird als Startmethode akzeptiert. Ein Methodenkopf wie public static void Main(String[] args) ist syntaktisch gültig, aber eben keiner, den die JVM zum Start ansteuern würde. Findet die JVM die Startmethode nicht, gibt sie eine Fehlermeldung aus:
Fehler: Hauptmethode in Klasse ABC nicht gefunden. Definieren Sie die Hauptmethode als:
public static void main(String[] args)
[»] Hinweis
Im Gegensatz zu C(++) steht im ersten Element des Argument-Arrays mit dem Index 0 nicht der Programmname, also der Name der Hauptklasse, sondern bereits der erste Programmparameter der Kommandozeile.
4.7.2 Kommandozeilenargumente verarbeiten
Eine besondere Variable für die Anzahl der übergebenen Argumente der Kommandozeile ist nicht erforderlich, weil das String-Array-Objekt uns diese Information über length mitteilt. Um etwa alle übergebenen Argumente über die erweiterte for-Schleife auszugeben, schreiben wir:
public static void main( String[] args ) {
if ( args.length == 0 )
System.out.println( "Was!! Keiner liebt kleine Hamster?" );
else {
System.out.print( "Liebt kleine Hamster: " );
for ( String s : args )
System.out.printf( "%s ", s );
System.out.println();
}
}
Das Programm lässt sich auf der Kommandozeile wie folgt aufrufen:
$ java com.tutego.insel.array.LovesGoldenHamster Raphael Perly Mirjam Paul
[»] Bibliothek
Zum Parsen der Kommandozeilenargumente bieten sich zum Beispiel die Bibliotheken Commons CLI (http://commons.apache.org/proper/commons-cli) oder picocli (http://picocli.info) an.
4.7.3 Der Rückgabetyp von main(…) und System.exit(int) *
Der Rückgabetyp void der Startmethode main(…) ist sicherlich diskussionswürdig, da diejenigen, die die Sprache entworfen haben, auch hätten fordern können, dass ein Programm immer einen Statuscode an das aufrufende Programm zurückgibt. Für diese Lösung haben sie sich aber nicht entschieden, da Java-Programme in der Regel nur minimal mit dem umgebenden Betriebssystem interagieren sollen und echte Plattformunabhängigkeit gefordert ist, etwa bei Java in Java-Programmen auf Smartphones.
Für die Fälle, in denen ein Statuscode zurückgeliefert werden soll, steht die statische Methode System.exit(status) zur Verfügung; sie beendet eine Applikation. Das an exit(int) übergebene Argument nennt sich Statuswert (engl. exit status) und wird an die Kommandozeile zurückgegeben. Der Wert ist für Skriptprogramme wichtig, da sie über diesen Rückgabewert auf das Gelingen oder Misslingen des Java-Programms reagieren können. Ein Wert von 0 zeigt per Definition das Gelingen an, ein Wert ungleich 0 einen Fehler. Der Wertebereich sollte sich zwischen 0 und 255 bewegen. Auf der Unix-Kommandozeile ist der Rückgabewert eines Programms unter $? verfügbar und in der cmd.exe von Windows unter %ERRORLEVEL%, einer Art dynamischer Umgebungsvariablen.
Dazu ein Beispiel; ein Java-Programm liefert den Statuswert 42:
package com.tutego.insel.array;
public class SystemExitDemo {
public static void main( String[] args ) {
System.exit( 42 );
}
}
Das folgende Shell-Programm gibt den Statuswert zunächst aus und zeigt zudem, welche Fallunterscheidung die Shell für Statuswerte bietet:
@echo off
cd target\classes
java com.tutego.insel.array.SystemExitDemo
echo %ERRORLEVEL%
if errorlevel 10 (
echo Exit-Code ist über 10, genau %ERRORLEVEL%
)
Die JVM startet das Java-Programm und beendet es mit System.exit(int), was zu einer Belegung der Variablen %ERRORLEVEL% mit 42 führt. Das Skript gibt zunächst die Belegung der Variablen aus. Die Windows-Shell besitzt mit if errorlevel Wert eine spezielle Variante für Fallunterscheidungen mit Exit-Codes, die genau dann greift, wenn der aktuelle Exit-Code größer oder gleich dem angegebenen Wert ist. Das heißt in unserem Beispiel: Es gibt eine Ausgabe, wenn der Exit-Code größer 10 ist, und mit 42 ist er das. Daher folgt die Ausgabe des kleinen Skripts:
>showreturn.bat
42
Error-Level ist über 10, genau 42
Es ist wichtig, zu bedenken, dass %ERRORLEVEL% natürlich überschrieben wird, wenn Befehle folgen. So gibt Folgendes nur 0 aus, da dir erfolgreich abgeschlossen werden kann und dir nach der Durchführung den Exit-Code auf 0 setzt:
java SystemExitDemo
dir
echo %ERRORLEVEL%
Liegen zwischen dem Aufruf der JVM und der Auswertung der Variablen Aufrufe, die den Exit-Code verändern, dann ist es sinnvoll, den Inhalt von %ERRORLEVEL% zwischenzuspeichern, etwa so:
@echo off
cd target\classes
java SystemExitDemo
SET EXITCODE=%ERRORLEVEL%
dir > NUL:
echo %ERRORLEVEL%
echo %EXITCODE%
Die Ausgabe ist dann:
0
42
final class java.lang.System
static void exit(int status)
Beendet die aktuelle JVM und gibt das Argument der Methode als Statuswert zurück. Ein Wert ungleich 0 zeigt einen Fehler an. Also ist der Rückgabewert beim normalen fehlerfreien Verlassen 0. Eine SecurityException wird ausgelöst, falls der aktuelle SecurityManager dem aufrufenden Code nicht erlaubt, die JVM zu beenden. Das gilt insbesondere bei Programmen in einem Container, wie einem Webserver.