Ich finde oft, dass es beim Debuggen eines Programms praktisch ist (obwohl dies wohl eine schlechte Praxis ist), eine return-Anweisung in einen Codeblock einzufügen. Ich könnte so etwas in Java versuchen ...
class Test {
public static void main(String args[]) {
System.out.println("hello world");
return;
System.out.println("i think this line might cause a problem");
}
}
Dies würde natürlich den Compilerfehler ergeben.
Test.java:7: nicht erreichbare Anweisung
Ich könnte verstehen, warum eine Warnung gerechtfertigt sein könnte, da unbenutzter Code eine schlechte Praxis ist. Aber ich verstehe nicht, warum dies einen Fehler erzeugen muss.
Versucht dies nur Java, ein Kindermädchen zu sein, oder gibt es einen guten Grund, dies zu einem Compilerfehler zu machen?
Antworten:
Weil nicht erreichbarer Code für den Compiler bedeutungslos ist. Während es sowohl von größter Bedeutung als auch schwieriger ist, Code für Menschen aussagekräftig zu machen, als ihn für einen Compiler sinnvoll zu machen, ist der Compiler der wesentliche Konsument von Code. Die Entwickler von Java sind der Ansicht, dass Code, der für den Compiler nicht von Bedeutung ist, ein Fehler ist. Ihre Haltung ist, dass Sie einen Fehler gemacht haben, der behoben werden muss, wenn Sie einen nicht erreichbaren Code haben.
Hier gibt es eine ähnliche Frage: Nicht erreichbarer Code: Fehler oder Warnung? , in dem der Autor sagt: "Ich persönlich bin der festen Überzeugung, dass es ein Fehler sein sollte: Wenn der Programmierer einen Code schreibt, sollte er immer die Absicht haben, ihn in einem bestimmten Szenario tatsächlich auszuführen." Offensichtlich sind sich die Sprachdesigner von Java einig.
Ob nicht erreichbarer Code die Kompilierung verhindern soll, ist eine Frage, über die es niemals einen Konsens geben wird. Aber deshalb haben es die Java-Designer getan.
Eine Reihe von Personen in Kommentaren weist darauf hin, dass es viele Klassen von nicht erreichbarem Code gibt. Java verhindert das Kompilieren nicht. Wenn ich die Konsequenzen von Gödel richtig verstehe, kann kein Compiler möglicherweise alle Klassen von nicht erreichbarem Code abfangen.
Unit-Tests können nicht jeden einzelnen Fehler erkennen. Wir verwenden dies nicht als Argument gegen ihren Wert. Ebenso kann ein Compiler nicht den gesamten problematischen Code abfangen, aber es ist dennoch wertvoll, um das Kompilieren von fehlerhaftem Code zu verhindern, wenn dies möglich ist.
Die Java-Sprachdesigner betrachten nicht erreichbaren Code als Fehler. Es ist also sinnvoll, das Kompilieren nach Möglichkeit zu verhindern.
(Bevor Sie abstimmen: Die Frage ist nicht, ob Java einen nicht erreichbaren Anweisungs-Compiler-Fehler haben sollte oder nicht. Die Frage ist, warum Java einen nicht erreichbaren Anweisungs-Compiler-Fehler hat. Stimmen Sie mich nicht ab, nur weil Sie glauben, dass Java die falsche Entwurfsentscheidung getroffen hat.)
quelle
return; System.out.println();
undif(true){ return; } System.out.println();
garantiert dasselbe Verhalten aufweisen, aber einer ist ein Kompilierungsfehler und der andere nicht. Wenn ich also debugge und mit dieser Methode Code vorübergehend "auskommentiere", mache ich das so. Das Problem beim Auskommentieren von Code besteht darin, dass Sie den geeigneten Ort finden müssen, um Ihren Kommentar zu stoppen. Dies kann länger dauern, als wenn Sie einenreturn;
schnellen Vorgang ausführen .Es gibt keinen endgültigen Grund, warum nicht erreichbare Aussagen nicht erlaubt sein dürfen; andere Sprachen erlauben sie ohne Probleme. Für Ihren speziellen Bedarf ist dies der übliche Trick:
Es sieht unsinnig aus, jeder, der den Code liest, wird vermuten, dass er absichtlich gemacht wurde, nicht ein unachtsamer Fehler, den Rest der Aussagen unerreichbar zu lassen.
Java unterstützt ein wenig die "bedingte Kompilierung"
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21
quelle
if (true) return;
zeigt nicht an, WARUM Sie die Logik überspringen, währendif (BEHAVIOURDISABLED) return;
die Absicht kommuniziert wird.Es ist Nanny. Ich habe das Gefühl, dass .Net dies richtig verstanden hat - es gibt eine Warnung für nicht erreichbaren Code aus, aber keinen Fehler. Es ist gut, davor gewarnt zu werden, aber ich sehe keinen Grund, die Kompilierung zu verhindern (insbesondere während Debugging-Sitzungen, bei denen es hilfreich ist, eine Rückgabe zu werfen, um Code zu umgehen).
quelle
Ich habe diese Frage gerade erst bemerkt und wollte meine $ .02 dazu hinzufügen.
Im Fall von Java ist dies eigentlich keine Option. Der Fehler "Nicht erreichbarer Code" beruht nicht auf der Tatsache, dass JVM-Entwickler dachten, Entwickler vor irgendetwas zu schützen oder besonders wachsam zu sein, sondern auf den Anforderungen der JVM-Spezifikation.
Sowohl der Java-Compiler als auch JVM verwenden sogenannte "Stack-Maps" - eine eindeutige Information über alle Elemente auf dem Stack, die für die aktuelle Methode zugewiesen wurden. Der Typ jedes einzelnen Steckplatzes des Stapels muss bekannt sein, damit ein JVM-Befehl Elemente eines Typs nicht mit einem anderen Typ misshandelt. Dies ist vor allem wichtig, um zu verhindern, dass jemals ein numerischer Wert als Zeiger verwendet wird. Mit der Java-Assembly können Sie versuchen, eine Nummer zu pushen / speichern, dann aber eine Objektreferenz einfügen / laden. JVM lehnt diesen Code jedoch während der Klassenüberprüfung ab. In diesem Fall werden Stapelzuordnungen erstellt und auf Konsistenz getestet.
Um die Stapelzuordnungen zu überprüfen, muss die VM alle in einer Methode vorhandenen Codepfade durchlaufen und sicherstellen, dass die Stapeldaten für jede Anweisung unabhängig davon, welcher Codepfad jemals ausgeführt wird, mit dem übereinstimmen, was der vorherige Code gepusht hat / im Stapel gespeichert. Also, im einfachen Fall von:
In Zeile 3 prüft JVM, ob beide Zweige von 'if' nur in einem (nur lokalen var # 0) Objekt gespeichert sind, das mit Object kompatibel ist (da Code ab Zeile 3 auf diese Weise lokales var # 0 behandelt ).
Wenn der Compiler zu einem nicht erreichbaren Code gelangt, weiß er nicht genau, welchen Status der Stapel zu diesem Zeitpunkt haben könnte, sodass er seinen Status nicht überprüfen kann. Zu diesem Zeitpunkt kann der Code nicht mehr vollständig kompiliert werden, da er auch die lokalen Variablen nicht verfolgen kann. Anstatt diese Mehrdeutigkeit in der Klassendatei zu belassen, wird ein schwerwiegender Fehler ausgegeben.
Natürlich wird eine einfache Bedingung
if (1<2)
es täuschen, aber es täuscht nicht wirklich - es gibt ihm einen potenziellen Zweig, der zum Code führen kann, und zumindest können sowohl der Compiler als auch die VM bestimmen, wie die Stapelelemente von dort aus verwendet werden können auf.PS Ich weiß nicht, was .NET in diesem Fall tut, aber ich glaube, dass die Kompilierung ebenfalls fehlschlagen wird. Dies ist normalerweise kein Problem für Maschinencode-Compiler (C, C ++, Obj-C usw.).
quelle
{ [flowingstatement;]* }
=>flowingstatement
,{ [flowingstatement;]* stoppingstatement; }
=>stoppingstatement
,return
=>stoppingstatement
,if (condition) stoppingstatement; else stoppingstatement
=>stoppingstatement;
usw.?void blah() { try {return;} catch (RuntimeError ex) { } DoSomethingElse(); }
Würde Java kreischen, dass es keine Möglichkeit gibt, dentry
Block tatsächlich über eine Ausnahme zu beenden, oder würde er annehmen, dass irgendeine Art von ungeprüfter Ausnahme innerhalb einestry
Blocks auftreten könnte ?if (constantThatEqualsFive < 3) {doSomething;};
.Eines der Ziele von Compilern ist es, Fehlerklassen auszuschließen. Es ist aus Versehen ein nicht erreichbarer Code vorhanden. Es ist schön, dass javac diese Fehlerklasse beim Kompilieren ausschließt.
Für jede Regel, die fehlerhaften Code abfängt, möchte jemand, dass der Compiler ihn akzeptiert, weil er weiß, was er tut. Das ist die Strafe für die Compilerprüfung, und das richtige Gleichgewicht zu finden, ist einer der Trickpunkte beim Sprachdesign. Selbst bei strengster Überprüfung können immer noch unendlich viele Programme geschrieben werden, so dass es nicht so schlimm sein kann.
quelle
Obwohl ich denke, dass dieser Compilerfehler eine gute Sache ist, gibt es eine Möglichkeit, ihn zu umgehen. Verwenden Sie eine Bedingung, von der Sie wissen, dass sie wahr ist:
Der Compiler ist nicht klug genug, sich darüber zu beschweren.
quelle
1<2
wahr ist, und der Rest der Methode muss nicht im Bytecode enthalten sein. Die Regeln für "nicht erreichbare Anweisungen" müssen klar, fest und unabhängig von der Intelligenz von Compilern sein.Es ist sicherlich eine gute Sache, sich zu beschweren, je strenger der Compiler ist, desto besser, soweit es Ihnen ermöglicht, das zu tun, was Sie brauchen. Normalerweise ist der geringe Preis, den Code zu kommentieren, der Vorteil, dass beim Kompilieren Ihr Code funktioniert. Ein allgemeines Beispiel ist Haskell, über das die Leute schreien, bis sie erkennen, dass ihr Test / Debugging nur ein Haupttest und ein kurzer Test ist. Ich persönlich mache in Java fast kein Debugging, während ich (tatsächlich absichtlich) nicht aufmerksam bin.
quelle
Wenn der Grund für das Zulassen darin
if (aBooleanVariable) return; someMoreCode;
besteht, Flags zuzulassen,if (true) return; someMoreCode;
scheint die Tatsache, dass kein Kompilierungszeitfehler generiert wird, eine Inkonsistenz in der Richtlinie zum Generieren der CodeNotReachable-Ausnahme zu sein, da der Compiler weiß, dass diestrue
kein Flag (keine Variable) ist.Zwei andere Möglichkeiten, die interessant sein könnten, aber nicht für das Ausschalten eines Teils des Codes einer Methode gelten, sowie
if (true) return
:Anstatt zu sagen
if (true) return;
, möchten Sie jetzt vielleicht sagenassert false
und hinzufügen-ea OR -ea package OR -ea className
zu den jvm-Argumenten . Der gute Punkt ist, dass dies eine gewisse Granularität ermöglicht und das Hinzufügen eines zusätzlichen Parameters zum JVM-Aufruf erfordert, sodass kein DEBUG-Flag im Code gesetzt werden muss, sondern ein zusätzliches Argument zur Laufzeit, was nützlich ist, wenn das Ziel nicht das ist Entwicklermaschine und das Neukompilieren und Übertragen von Bytecode braucht Zeit.Es gibt auch den
System.exit(0)
Weg, aber dies könnte ein Overkill sein. Wenn Sie es in Java in einer JSP ablegen, wird der Server beendet.Abgesehen davon, dass Java von Natur aus eine 'Nanny'-Sprache ist, würde ich lieber etwas Natives wie C / C ++ verwenden, um mehr Kontrolle zu haben.
quelle
static final
Variablen, die in einem statischen Initialisierungsblock festgelegt ist, zu einerstatic final
Variablen, die in seiner Deklaration festgelegt ist, sollte keine grundlegende Änderung sein. Es ist durchaus plausibel, dass eine Klasse beim ersten Schreiben manchmal nicht in der Lage war, etwas zu tun (und erst zur Laufzeit wusste, ob sie dazu in der Lage wäre oder nicht), aber spätere Versionen der Klasse waren möglicherweise dazu in der Lage Mach diese Aktion immer. Das ÄndernmyClass.canFoo
einer Konstante sollteif (myClass.canFoo) myClass.Foo(); else doSomethingElse();
effizienter sein - nicht brechen.