Jaka jest alternatywna funkcja słowa kluczowego goto w Javie?
Ponieważ Java nie ma goto.
Jaka jest alternatywna funkcja słowa kluczowego goto w Javie?
Ponieważ Java nie ma goto.
Odpowiedzi:
Możesz użyć oznaczonego BREAK oświadczenia:
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;
}
}
}
Jednak w odpowiednio zaprojektowanym kodzie nie powinieneś potrzebować funkcjonalności GOTO.
Nie ma bezpośredniego odpowiednika tego goto
pojęcia w Javie. Istnieje kilka konstrukcji, które umożliwiają wykonanie niektórych czynności, które można wykonać za pomocą klasyki goto
.
break
i continue
umożliwiają wyjście z bloku w pętli lub instrukcji switch.break <label>
umożliwia wyskoczenie z dowolnej instrukcji złożonej na dowolny poziom w ramach danej metody (lub bloku inicjalizatora).continue <label>
kontynuować następną iterację zewnętrznej pętli z pętli wewnętrznej.return
.Żadna z tych konstrukcji Java nie pozwala na rozgałęzienie wstecz lub do punktu w kodzie na tym samym poziomie zagnieżdżenia, co bieżąca instrukcja. Wszystkie wyskakują z jednego lub więcej poziomów zagnieżdżenia (zakresu) i wszystkie (oprócz continue
) skaczą w dół. To ograniczenie pomaga uniknąć syndromu „kodu spaghetti” goto, nieodłącznie związanego ze starymi kodami BASIC, FORTRAN i COBOL 2 .
1- Najdroższą częścią wyjątków jest faktyczne utworzenie obiektu wyjątku i jego ślad stosu. Jeśli naprawdę, naprawdę potrzebujesz obsługi wyjątków do „normalnej” kontroli przepływu, możesz albo wstępnie przydzielić / ponownie użyć obiektu wyjątku, albo utworzyć niestandardową klasę wyjątków, która przesłania fillInStackTrace()
metodę. Wadą jest to, że metody wyjątku printStackTrace()
nie dostarczą przydatnych informacji ... jeśli kiedykolwiek będziesz musiał je wywołać.
2 - Syndrom kodu spaghetti zapoczątkował podejście do programowania strukturalnego , w którym ograniczyłeś wykorzystanie dostępnych konstrukcji językowych. Można to zastosować do języka BASIC , Fortran i COBOL , ale wymagało to ostrożności i dyscypliny. Całkowite pozbycie goto
się było pragmatycznie lepszym rozwiązaniem. Jeśli zachowasz to w języku, zawsze znajdzie się jakiś klaun, który będzie go nadużywał.
Dla zabawy, oto implementacja GOTO w Javie.
Przykład:
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 }
Uruchamianie:
$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo 3 2 1 0 Hello World!
Czy muszę dodawać „nie używaj tego!”?
Math.random()
może zwrócić 0. Powinno być> =
Chociaż niektórzy twierdzą, komentujących i downvoters że to nie jest goto wygenerowany kod bajtowy z niżej stwierdzeń Java rzeczywiście sugeruje, że te wypowiedzi rzeczywiście wyrażają goto semantykę.
W szczególności do {...} while(true);
pętla w drugim przykładzie jest optymalizowana przez kompilatory języka Java, aby nie oceniać warunku pętli.
label: {
// do stuff
if (check) break label;
// do more stuff
}
W kodzie bajtowym:
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);
W kodzie bajtowym:
2 iload_1 [check]
3 ifeq 9
6 goto 2 // Jumping backward
9 ..
continue label
to skok w tył
// do stuff
i // do more stuff
są, continue label
„skutkuje” przeskakiwaniem do tyłu (ze względu na while(true)
stwierdzenie oczywiście). Nie zdawałem sobie jednak sprawy, że to było tak precyzyjne pytanie ...
while(true)
on tłumaczony przez kompilator na goto
operację kodu bajtowego. Ponieważ true
jest to stały literał, kompilator może przeprowadzić tę optymalizację i nie musi niczego oceniać. Więc, mój przykład naprawdę jest goto, skacząc wstecz ...
Jeśli naprawdę chcesz czegoś takiego jak instrukcje goto, zawsze możesz spróbować rozbić na nazwane bloki.
Aby przejść do etykiety, musisz znajdować się w zakresie bloku:
namedBlock: {
if (j==2) {
// this will take you to the label above
break namedBlock;
}
}
Nie będę cię pouczał, dlaczego powinieneś unikać goto - zakładam, że znasz już odpowiedź na to pytanie.
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 pisze:
Istnieją dwie konstrukcje, które umożliwiają wykonanie niektórych czynności, które można wykonać za pomocą klasycznego goto.
Jeszcze jeden...
Matt Wolfe pisze:
Ludzie zawsze mówią, że nigdy nie używają goto, ale myślę, że istnieje naprawdę dobry przypadek użycia w świecie rzeczywistym, który jest dość dobrze znany i używany. Oznacza to, że należy wykonać kod przed powrotem z funkcji. Zwykle jest to wydanie zamki lub co nie, ale w moim przypadku chciałbym móc wskoczyć do przerwy tuż przed powrotem, aby móc wykonać wymagane obowiązkowe sprzątanie.
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
Ostatni blok jest zawsze wykonywany, gdy blok try kończy działanie. Gwarantuje to, że ostatni blok zostanie wykonany, nawet jeśli wystąpi nieoczekiwany wyjątek. Ale w końcu jest przydatny nie tylko do obsługi wyjątków - pozwala programistom uniknąć przypadkowego pominięcia kodu czyszczącego przez powrót, kontynuację lub przerwanie. Umieszczanie kodu porządkującego w bloku final jest zawsze dobrą praktyką, nawet jeśli nie przewiduje się żadnych wyjątków.
Głupie pytanie w rozmowie kwalifikacyjnej związane z wreszcie brzmi: Jeśli wrócisz z bloku try {}, ale uzyskasz zwrot również w swoim końcu {}, która wartość zostanie zwrócona?
return
w finally
bloku jest złym pomysłem. (I nawet jeśli wiedza nie jest absolutnie konieczna, martwiłbym się programistą, który nie miałby ciekawości, aby się dowiedzieć ...)
Najłatwiejszy to:
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;
}
}
Wypróbuj poniższy kod. Mi to pasuje.
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 nie ma goto
, ponieważ sprawia, że kod jest niestrukturalny i niejasny do odczytania. Możesz jednak używać break
i continue
jako cywilizowanej formy goto bez problemów.
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");
Wyjście :
Before Break
After ahead
before: {
System.out.println("Continue");
continue before;
}
Spowoduje to nieskończoną pętlę, ponieważ za każdym razem, gdy linia continue before
jest wykonywana, przepływ kodu rozpocznie się ponownie odbefore
.
goto
był dostępny w Javie? Myślę, że na tym polega ważniejsza kwestia.