Was ist eine alternative Funktion für das Schlüsselwort goto in Java?
Da hat Java kein goto.
Was ist eine alternative Funktion für das Schlüsselwort goto in Java?
Da hat Java kein goto.
Antworten:
Sie können eine beschriftete BREAK- Anweisung verwenden:
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}
In richtig entworfenem Code sollten Sie jedoch keine GOTO-Funktionalität benötigen.
goto
In Java gibt es kein direktes Äquivalent zum Konzept. Es gibt einige Konstrukte, mit denen Sie einige der Dinge tun können, die Sie mit einem Klassiker tun können goto
.
break
und continue
können Sie in einer Schleifen- oder switch-Anweisung aus einem Block springen.break <label>
, mit der Sie aus einer beliebigen zusammengesetzten Anweisung auf eine beliebige Ebene innerhalb einer bestimmten Methode (oder eines Initialisierungsblocks) springen können.continue <label>
mit der nächsten Iteration einer äußeren Schleife von einer inneren Schleife fortfahren.return
.Mit keinem dieser Java-Konstrukte können Sie rückwärts oder zu einem Punkt im Code auf derselben Verschachtelungsebene wie die aktuelle Anweisung verzweigen. Sie alle springen aus einer oder mehreren Verschachtelungsebenen (Scope) und alle (abgesehen von continue
) nach unten. Diese Einschränkung hilft, das Goto-Spaghetti-Code-Syndrom zu vermeiden, das dem alten BASIC-, FORTRAN- und COBOL-Code 2 innewohnt .
1- Der teuerste Teil von Ausnahmen ist die tatsächliche Erstellung des Ausnahmeobjekts und seiner Stapelverfolgung. Wenn Sie die Ausnahmebehandlung wirklich, wirklich für die "normale" Flusssteuerung verwenden müssen, können Sie das Ausnahmeobjekt entweder vorab zuordnen / wiederverwenden oder eine benutzerdefinierte Ausnahmeklasse erstellen, die die fillInStackTrace()
Methode überschreibt . Der Nachteil ist, dass die printStackTrace()
Methoden der Ausnahme keine nützlichen Informationen liefern ... falls Sie sie jemals aufrufen müssen.
2 - Das Spaghetti-Code-Syndrom hat den strukturierten Programmieransatz hervorgebracht , bei dem Sie die Verwendung der verfügbaren Sprachkonstrukte eingeschränkt haben. Dies könnte auf BASIC , Fortran und COBOL angewendet werden, erfordert jedoch Sorgfalt und Disziplin. goto
Ganz loszuwerden war eine pragmatisch bessere Lösung. Wenn Sie es in einer Sprache halten, gibt es immer einen Clown, der es missbraucht.
Nur zum Spaß, hier ist eine GOTO-Implementierung in Java.
Beispiel:
1 public class GotoDemo { 2 public static void main(String[] args) { 3 int i = 3; 4 System.out.println(i); 5 i = i - 1; 6 if (i >= 0) { 7 GotoFactory.getSharedInstance().getGoto().go(4); 8 } 9 10 try { 11 System.out.print("Hell"); 12 if (Math.random() > 0) throw new Exception(); 13 System.out.println("World!"); 14 } catch (Exception e) { 15 System.out.print("o "); 16 GotoFactory.getSharedInstance().getGoto().go(13); 17 } 18 } 19 }
Ausführen:
$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo 3 2 1 0 Hello World!
Muss ich hinzufügen "benutze es nicht!"?
Math.random()
Während einige Kommentatoren und Downvoter argumentieren, dass dies nicht goto ist , deutet der generierte Bytecode aus den folgenden Java-Anweisungen wirklich darauf hin, dass diese Anweisungen wirklich goto- Semantik ausdrücken .
Insbesondere wird die do {...} while(true);
Schleife im zweiten Beispiel von Java-Compilern optimiert, um die Schleifenbedingung nicht zu bewerten.
label: {
// do stuff
if (check) break label;
// do more stuff
}
Im Bytecode:
2 iload_1 [check]
3 ifeq 6 // Jumping forward
6 ..
label: do {
// do stuff
if (check) continue label;
// do more stuff
break label;
} while(true);
Im Bytecode:
2 iload_1 [check]
3 ifeq 9
6 goto 2 // Jumping backward
9 ..
continue label
ist der Sprung zurück
// do stuff
und // do more stuff
sind die Aussagen von Interesse, continue label
" hat den Effekt " , rückwärts zu springen (aufgrund der while(true)
Aussage natürlich). Mir war jedoch nicht bewusst, dass dies eine so genaue Frage war ...
while(true)
wird vom Compiler in eine goto
Bytecode-Operation übersetzt. Da true
es sich um ein konstantes Literal handelt, kann der Compiler diese Optimierung durchführen und muss nichts auswerten. Also, mein Beispiel ist wirklich ein Goto, rückwärts springen ...
Wenn Sie wirklich so etwas wie goto-Anweisungen wollen, können Sie immer versuchen, in benannte Blöcke zu brechen.
Sie müssen sich im Rahmen des Blocks befinden, um zum Label zu gelangen:
namedBlock: {
if (j==2) {
// this will take you to the label above
break namedBlock;
}
}
Ich werde Ihnen nicht erklären, warum Sie Goto vermeiden sollten - ich gehe davon aus, dass Sie die Antwort darauf bereits kennen.
public class TestLabel {
enum Label{LABEL1, LABEL2, LABEL3, LABEL4}
/**
* @param args
*/
public static void main(String[] args) {
Label label = Label.LABEL1;
while(true) {
switch(label){
case LABEL1:
print(label);
case LABEL2:
print(label);
label = Label.LABEL4;
continue;
case LABEL3:
print(label);
label = Label.LABEL1;
break;
case LABEL4:
print(label);
label = Label.LABEL3;
continue;
}
break;
}
}
public final static void print(Label label){
System.out.println(label);
}
StephenC schreibt:
Es gibt zwei Konstrukte, mit denen Sie einige der Dinge tun können, die Sie mit einem klassischen goto tun können.
Einer noch...
Matt Wolfe schreibt:
Die Leute reden immer davon, niemals ein goto zu verwenden, aber ich denke, es gibt einen wirklich guten realen Anwendungsfall, der ziemlich bekannt und verwendet ist. Das heißt, Sie müssen sicherstellen, dass Sie Code ausführen, bevor Sie von einer Funktion zurückkehren. Normalerweise wird er freigegeben Schlösser oder was nicht, aber in meinem Fall würde ich gerne kurz vor der Rückkehr zu einer Pause springen können, damit ich die erforderliche obligatorische Bereinigung durchführen kann.
try {
// do stuff
return result; // or break, etc.
}
finally {
// clean up before actually returning, even though the order looks wrong.
}
http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
Der finally-Block wird immer ausgeführt, wenn der try-Block beendet wird. Dadurch wird sichergestellt, dass der finally-Block auch dann ausgeführt wird, wenn eine unerwartete Ausnahme auftritt. Aber schließlich ist es nicht nur für die Ausnahmebehandlung nützlich - es ermöglicht dem Programmierer zu vermeiden, dass der Bereinigungscode versehentlich durch eine Rückgabe umgangen, fortgesetzt oder unterbrochen wird. Das Einfügen von Bereinigungscode in einen finally-Block ist immer eine gute Vorgehensweise, auch wenn keine Ausnahmen zu erwarten sind.
Die dumme Interviewfrage, die mit finally verbunden ist, lautet: Wenn Sie von einem try {} -Block zurückkehren, aber auch eine return in Ihrem finally {} haben, welcher Wert wird zurückgegeben?
return
eines finally
Blocks eine schlechte Idee ist. (Und selbst wenn das Wissen nicht unbedingt notwendig ist, würde ich mir Sorgen um einen Programmierer machen, der nicht die Neugier hatte, es herauszufinden ...)
Am einfachsten ist:
int label = 0;
loop:while(true) {
switch(state) {
case 0:
// Some code
state = 5;
break;
case 2:
// Some code
state = 4;
break;
...
default:
break loop;
}
}
Versuchen Sie den folgenden Code. Für mich geht das.
for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is 8 Taksa
strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa];
LabelEndTaksa_Exit : {
if (iCountTaksa == 1) { //If count is 6 then next it's 2
iCountTaksa = 2;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 2) { //If count is 2 then next it's 3
iCountTaksa = 3;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 3) { //If count is 3 then next it's 4
iCountTaksa = 4;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 4) { //If count is 4 then next it's 7
iCountTaksa = 7;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 7) { //If count is 7 then next it's 5
iCountTaksa = 5;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 5) { //If count is 5 then next it's 8
iCountTaksa = 8;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 8) { //If count is 8 then next it's 6
iCountTaksa = 6;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 6) { //If count is 6 then loop 1 as 1 2 3 4 7 5 8 6 --> 1
iCountTaksa = 1;
break LabelEndTaksa_Exit;
}
} //LabelEndTaksa_Exit : {
} // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"
Java hat keine goto
, weil es den Code unstrukturiert und unklar zu lesen macht. Sie können jedoch break
und continue
als zivilisierte Form von goto ohne seine Probleme verwenden.
ahead: {
System.out.println("Before break");
break ahead;
System.out.println("After Break"); // This won't execute
}
// After a line break ahead, the code flow starts from here, after the ahead block
System.out.println("After ahead");
Ausgabe :
Before Break
After ahead
before: {
System.out.println("Continue");
continue before;
}
Dies führt zu einer Endlosschleife, da bei jeder continue before
Ausführung der Zeile der Code-Fluss von neu gestartet wirdbefore
.
goto
in Java verfügbar wäre ? Ich denke, darin liegt das wichtigere Thema.