Es läuft nicht für immer. Jedes StackOverflow führt dazu, dass der Code zum finally-Block wechselt. Das Problem ist, dass es eine wirklich, wirklich lange Zeit dauern wird. Die Zeitkomplexität beträgt O(2^N), wobei N die maximale Stacktiefe ist.
Stellen Sie sich vor, die maximale Tiefe beträgt 5
foo() ruft auf
foo() ruft auf
foo() ruft auf
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
schließlich
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() ruft auf
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
schließlich
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() ruft auf
foo() ruft auf
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
schließlich
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() ruft auf
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
schließlich
foo() ruft auf
foo() auf, das es nicht schafft, foo() aufzurufen
ruft schließlich auf
foo() auf, das es nicht schafft, foo() aufzurufen
Um jedes Level in den finally-Block zu bringen, dauert doppelt so lange wie die Stacktiefe und könnte 10.000 oder mehr betragen. Wenn Sie pro Sekunde 10.000.000 Aufrufe machen können, dauert es 10^3003 Sekunden oder länger als das Alter des Universums.
0 Stimmen
Erlaubt die JVM keine Optimierung von Endaufrufen? Das würde die endlose Rekursion in eine endlose Schleife umwandeln.
17 Stimmen
Formell wird das Programm letztendlich stoppen, da Fehler, die während der Verarbeitung der
finally
Klausel auftreten, an die nächste höhere Ebene weitergeleitet werden. Aber halten Sie nicht den Atem an; die Anzahl der Schritte beträgt etwa 2 zur (maximalen Stapeltiefe) und das Werfen von Ausnahmen ist auch nicht gerade billig.0 Stimmen
@dan04 Während es dies ermöglichen könnte, was lässt dich glauben, dass es sich um eine korrekte Optimierung handelt? (Hinweis: Das ist es nicht, da das Ende des
finally
Blocks nicht frei ist.)3 Stimmen
Es wäre jedoch "korrekt" für
bar()
.6 Stimmen
@dan04: Java führt keine TCO durch, soweit ich mich erinnere, um sicherzustellen, dass vollständige Stapelverfolgungen vorliegen, und für etwas im Zusammenhang mit Reflektion (wahrscheinlich auch mit Stapelverfolgungen).
4 Stimmen
Interessanterweise stürzte das Programm beim Test auf .Net (mit Mono) mit einem StackOverflow-Fehler ab, ohne jemals finally aufzurufen.
0 Stimmen
@Kibbee eine völlig andere Laufzeitbibliothek. Ich bin mir zu 99% sicher, dass man bei .NET Stacküberläufe nicht abfangen kann.
2 Stimmen
@Kibbee Das ist beabsichtigt. Von StackOverflowException: "Beginnend mit dem .NET Framework Version 2.0 kann ein StackOverflowException-Objekt nicht von einem try-catch-Block eingefangen werden und der entsprechende Prozess wird standardmäßig beendet." Ich glaube, dass Sie im .NET 1.1 dasselbe Verhalten wie in Java erhalten würden.
1 Stimmen
Dies ist eines der Rätsel im Buch
Java™ Puzzlers: Traps, Pitfalls, and Corner Cases
11 Stimmen
Das ist das schlechteste Stück Code, das ich je gesehen habe :)