- System.exit(...);
Also um zu verstehen, warum der Compiler die Änderung des Programmflusses nicht erkennt, gilts erstmal zu wissen, was ein Compiler macht und wie er es macht. Ein Compiler besteht zunächst erstmal aus 3 Komponenten: Scanner, Parser, Codegenerator.
Der Scanner liest die Datei zeichenweise ein und scannt die Datei zunächst nach ungültigen Zeichen. Hier sind also Fehlermeldungen angesiedelt, dass z.B. ein Variablenname ungültig ist ("public int #ofElems();"). Desweiteren "bastelt" er aus einzelnen Zeichen Wörter zusammen, die dann an den Parser weitergegeben werden. Also z.B. beim zeichenweisen Einlesen erkennt der Scanner, dass "p u b l i c" ein Wort der Sprache ist und gibt das als "public" an den Parser weiter. Ebenso ist "int" ein Wort der Sprache.
Der Parser baut dann einen sogenannten Syntax- oder Parsebaum auf, der den gesamten Code als Baum repräsentiert. Dieser Baum geht dann an den Codegenerator. Der Codegenerator transformiert dann den Baum in Code der gewünschten Zielsprache (z.B. Assembler, JVM assembler, .NET assembler; gibt aber auch Sprachen, deren Compilerimplementationen z.B. C generieren Gwydion Dylan). Bei Erstellung des Baums bzw. beim Prüfen der Struktur des Baums kommen dann z.B. Fehlermeldungen raus, dass eine Variable nicht deklariert wurde oder dass eine bestimmte Methode nicht aufgerufen werden kann, weil die Anzahl der Parameter falsch ist.
Was denn nun ein ungültiges Zeichen oder ein gültiges Zeichen ist und was denn nun Wort einer Sprache ist oder nicht, wird in einer sogenannten Grammatik beschrieben. Eine mögliche Notation für eine Grammatik ist z.B. die BNF, die auch die Notationsmethode für die Javagrammatik ist.
Scanner und Parser werden auf Basis der Grammatik generiert und nur noch der Codegenerator und Strukturprüfung ist etwas, was noch handgeschrieben ist. Die Fehlermeldung z.B. für dein Beispiel lautet:"missing return statement". Das ist eine Fehlermeldung, die typischerweise vom Parser beim Baumaufbau kommt und damit aus generiertem Code, da zu einer nicht-void Methode ein return statement gehört. Eine Erkennung, dass sich der Programmfluss aber geändert hat durch "System.exit(...)", ist an der Stelle schlicht und einfach nicht vorgesehen. Selbst wenn eine Erkennung implementiert wird, kann sie erst nach dem Baumaufbau kommen und ist damit zu spät.
So, mann, hab ich doch mehr ausgeholt, als ich wollte, aber ich hoffe, es ist jetzt klarer. ☺