ubuntuusers.de

Java: System.exit() & Programmfluß

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

PrairieDog

Anmeldungsdatum:
16. Februar 2006

Beiträge: 870

Kann mir hier einer beantworten, warum der Compiler System.exit(...) nicht als programmflußverändernd erkennt?

(Sinnfreies) Beispiel:

public boolean foo(){
   System.exit(0);
} 

Der Compiler meckert, will einen boolschen Wert zurückgegeben haben.

Die API sagt zu Sytem.exit(...): "This method never returns normally" - also beeinflußt sie doch den Programmfluß (recht markant, möchte man meinen).

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Naja, er hat doch recht. Gibt halt void zurück...
(deshalb ist main() auch vom Typ void.)

Greebo

Avatar von Greebo

Anmeldungsdatum:
21. November 2006

Beiträge: 3443

Wohnort: 97070 Würzburg

Ich vermute wegen

Throws:
SecurityException - if a security manager exists and its checkExit method doesn't allow exit with the specified status.

http://java.sun.com/javase/6/docs/api/java/lang/System.html#exit(int)

Gibt also doch noch einen Weg an System.exit vorbei.

Vermutlich hätten sie besser schreiben sollen

"This method normally never returns normally"

😈

PrairieDog

(Themenstarter)

Anmeldungsdatum:
16. Februar 2006

Beiträge: 870

Naja, aber was passiert denn dann? Die Exception wird geworfen, ich kehre nicht an diesen Punkt zurück.

Aus diesem Grund funktioniert ja auch ein:

public boolean foo(){
   throw new IllegalArgumentException();
} 

⇒ der Compiler beschwert sich nicht.

Greebo

Avatar von Greebo

Anmeldungsdatum:
21. November 2006

Beiträge: 3443

Wohnort: 97070 Würzburg

Auch wieder wahr 😕 . Spontan fällt mir da dann auch nichts mehr zu ein. Im Zweifelsfall würde ich aber behaupten, dass auch Compiler nicht perfekt sind 😉, und irgendwo müssen sie ja auch selbst Schranken in der Analyse vom AST setzen, sonst kommt ja nie was raus 😀 , aber ich guck nochmal, vielleicht steht ja was in der JLS zu

PrairieDog

(Themenstarter)

Anmeldungsdatum:
16. Februar 2006

Beiträge: 870

Also eher (wie ich mir das denke) eine philosophische Frage.

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

PrairieDog hat geschrieben:

Naja, aber was passiert denn dann? Die Exception wird geworfen, ich kehre nicht an diesen Punkt zurück.

Zur Übersetzungszeit ist weder bekannt, ob diese Ausnahme ausgelöst wird, der Prozess beendet wird, oder gar nichts passiert.

Die Restriktionen des Security-Managers hängen von der Laufzeitumgebung ab, ergo ist zur Übersetzungszeit nicht bekannt, ob eine Ausnahme ausgelöst wird. Ebenso wenig ist dem Compiler zur Übersetzungszeit die Laufzeitumgebung bekannt, er kann also nicht voraussetzen, dass ``exit`` wirklich den Abbruch des Prozesses zur Folge hat. Das Programm könnte ja auch in einer Embedded Umgebung laufen, in der ``exit`` nicht implementiert ist und einfach gar nichts macht.

Methoden sollten von außen eigentlich immer als frei von Nebeneffekten angesehen werden, weil diese Nebeneffekte wie eben der Programmabbruch zur Übersetzungszeit nicht vorhergesehen werden können. Deswegen geht der Compiler den sicheren Weg und erfordert ein explizites Statement zum Abschließen es Kontrollflusses.

stmaassen

Anmeldungsdatum:
12. Juni 2008

Beiträge: Zähle...

- 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. ☺

DoktorDanger

Anmeldungsdatum:
13. Juni 2008

Beiträge: 37

also ich geh da einfach ganz naiv dran.

public boolean foo(){
System.exit(0);
}
Die funktion boo sollte eigentlich nen wert zurückgeben. tut sie aber nicht. und das system.exit is auch nur nen funktionsaufruf, mehr nicht.

Antworten |