web-dev-qa-db-fra.com

Alternative à une instruction goto dans Java

Qu'est-ce qu'une fonction alternative pour le mot clé goto en Java?

Depuis Java n'a pas de goto.

83
gmhk

Vous pouvez utiliser une instruction BREAK :

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;
            }
        }
    }

Cependant, dans un code correctement conçu, vous ne devriez pas avoir besoin de la fonctionnalité GOTO.

82
Padmarag

Il n'y a pas d'équivalent direct au concept goto en Java. Il y a quelques constructions qui vous permettent de faire certaines choses que vous pouvez faire avec un goto classique.

  • Les instructions break et continue vous permettent de sortir d'un bloc dans une instruction loop ou switch.
  • Une instruction étiquetée et break <label> Vous permettent de sortir d'une instruction composée arbitraire vers n'importe quel niveau d'une méthode donnée (ou d'un bloc d'initialisation).
  • Si vous étiquetez une déclaration de boucle, vous pouvez continue <label> Pour continuer avec la prochaine itération d'une boucle externe à partir d'une boucle interne.
  • Lancer et intercepter des exceptions vous permet (efficacement) de sortir de plusieurs niveaux d'un appel de méthode. (Cependant, les exceptions sont relativement coûteuses et sont considérées comme une mauvaise façon de faire un flux de contrôle "ordinaire"1.)
  • Et bien sûr, il y a return.

Aucune de ces constructions Java) ne vous permet de basculer en arrière ou vers un point du code au même niveau d’imbrication que l’instruction en cours. Toutes dépassent un ou plusieurs niveaux d’imbrication (portée) et tous (sauf continue) sautent vers le bas. Cette restriction permet d'éviter le syndrome de goto "code spaghetti" inhérent aux anciens codes BASIC, FORTRAN et COBOL.2.


1- La partie la plus chère des exceptions est la création réelle de l'objet exception et de son stacktrace. Si vous devez réellement utiliser la gestion des exceptions pour un contrôle de flux "normal", vous pouvez soit pré-allouer/réutiliser l'objet exception, soit créer une classe d'exception personnalisée qui remplace la méthode fillInStackTrace(). L'inconvénient est que les méthodes printStackTrace() de l'exception ne vous donneront pas d'informations utiles ... si jamais vous deviez les appeler.

2 - Le syndrome du code spaghetti a engendré l'approche programmation structurée , dans laquelle vous avez limité votre utilisation des constructions de langage disponibles. Ceci pourrait être appliqué à DE BASE , Fortran et COBOL =, mais cela demandait soin et discipline. Se débarrasser entièrement de goto était une meilleure solution pragmatique. Si vous le gardez dans une langue, il y a toujours un clown qui en abusera.

41
Stephen C

Juste pour le plaisir, ici est une implémentation de GOTO en Java.

Exemple:

   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 }

Le lancer:

$ Java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo           
   3
   2
   1
   0
   Hello World!

Dois-je ajouter "ne l'utilisez pas!"?

29
Pascal Thivent

Alors que certains commentateurs et votants votants affirment que ce n'est pas goto, le bytecode généré à partir du code ci-dessous Java énonce vraiment que ces énoncés expriment vraiment goto sémantique.

Plus précisément, la boucle do {...} while(true); du deuxième exemple est optimisée par les compilateurs Java) afin de ne pas évaluer la condition de la boucle.

Sauter en avant

label: {
  // do stuff
  if (check) break label;
  // do more stuff
}

En bytecode:

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

Sauter en arrière

label: do {
  // do stuff
  if (check) continue label;
  // do more stuff
  break label;
} while(true);

En bytecode:

 2  iload_1 [check]
 3  ifeq 9
 6  goto 2          // Jumping backward
 9  ..
17
Lukas Eder

Si vous voulez vraiment quelque chose comme des instructions goto, vous pouvez toujours essayer de casser des blocs nommés.

Vous devez être dans la portée du bloc pour vous briser l'étiquette:

namedBlock: {
  if (j==2) {
    // this will take you to the label above
    break namedBlock;
  }
}

Je ne vous expliquerai pas pourquoi vous devriez éviter les goto - je suppose que vous connaissez déjà la réponse à cette question.

5
Amir Afghani
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);
    }
4
code lover

StephenC écrit:

Deux concepts vous permettent de faire certaines des choses que vous pouvez faire avec un goto classique.

Un de plus...

Matt Wolfe écrit:

Les gens parlent toujours de ne jamais utiliser un goto, mais je pense qu'il existe un très bon cas d'utilisation dans le monde réel, qui est assez bien connu et utilisé. serrures ou quoi, mais dans mon cas, j'aimerais pouvoir faire une pause juste avant le retour afin que je puisse effectuer le nettoyage obligatoire obligatoire.

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

Le bloc finally s'exécute toujours à la sortie du bloc try. Cela garantit que le bloc finally est exécuté même si une exception inattendue se produit. Mais finalement, c'est utile pour plus que la gestion des exceptions - cela permet au programmeur d'éviter que le code de nettoyage soit contourné accidentellement par un retour, une poursuite ou une interruption. Mettre le code de nettoyage dans un bloc finally est toujours une bonne pratique, même si aucune exception n'est anticipée.

La question idiote de l'entrevue associée à finally est la suivante: Si vous revenez d'un bloc try {}, mais que vous avez également un retour dans votre} {}, quelle valeur est renvoyée?

3
android.weasel

Le plus simple est:

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;
    }
}
1
ratchet freak

Essayez le code ci-dessous. Ça marche pour moi.

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++) {"
0
mahasam