Etichette Java. Essere o non essere [chiuso]

7

Prima di iniziare questa domanda, so che java 'goto' è un grande no.

Quindi sto scrivendo un programma e ho dei loop e delle istruzioni rientrate e ho bisogno di BREAK multiple su comando. Piuttosto che avere un carico di boolean variabili e if(!<booleanName>) BREAK; dichiarazioni in questi cicli e dichiarazioni, qual è l'opinione di tutti sull'uso delle etichette per romperle usando l'istruzione BREAK <label> ?

per es.

 for(...) {

      indented_example_loops:     // Label name
           for(...) {
                for(...) {
                     if(match) break indented_example_loops;
                     // ^ Break statement to break the 2 for loops at once
                }
           }

 }

Perfettamente ok? Va bene ogni tanto? Evitare completamente? o dovrei andare in un angolo e chiamare il diavolo per prendere l'anima?

    
posta Skepi 05.02.2013 - 10:21
fonte

4 risposte

22

Si tratta di leggibilità e facilità di comprensione.

I loop più facili da capire sono quelli con condizioni finali semplici e senza interruzioni. Quindi se puoi scrivere i tuoi loop in questo modo, fallo.

while (someCondition) {
  // do stuff
}

Il prossimo ciclo arriva con una semplice condizione di fine e una singola interruzione:

while (someCondition) {
  // do stuff
  if (otherCondition) {
    break;
  }
  // maybe some more stuff
}

Tutto ciò che è più complesso di questo è un potenziale problema. Una rottura con un'etichetta è sempre complicata, perché dovrai cercare l'etichetta per scoprire quale istruzione / bloccare la pausa fugge da (ovvero l'interruzione continuerà dopo il blocco / istruzione etichettato).

Il tipo peggiore (quello che quasi sempre vuole evitare) è un ciclo annidato in cui si interrompe da qualche parte nel mezzo .

while (someCondition) {
  myLabel:
  for (Foo foo : getAllFoos()) {
    for (Bar bar : foo.getBars()) {
      // do stuff
      if (someCondition(bar)) {
        break myLabel; // BAD!
      }
      // some more stuff
    }
  }
}

Il problema qui è che il vero flusso di elaborazione diventa davvero difficile da seguire. Se inizi ad avere un codice come questo, dovresti sicuramente ridefinirlo.

Un refactoring comune è quello di estrarre uno (o più) cicli annidati in un metodo e trasformare break in return . Questo ha l'ulteriore vantaggio di dare un nome a quel pezzo di codice. Se il nome è scelto bene, allora questo aiuterà molto a capire il codice.

    
risposta data 05.02.2013 - 10:30
fonte
6

Ti stai aprendo al codice spaghetti

Sebbene la lingua ti permetta di farlo, non è una buona pratica. Ci sono molte strutture di loop alternative che raggiungono lo stesso obiettivo e rendono il tuo codice molto più leggibile.

Essenzialmente, le etichette e il gotos sono un residuo del codice del linguaggio assembly (che riguarda le etichette e il gotos). Non ha davvero spazio nelle lingue di livello superiore.

    
risposta data 05.02.2013 - 10:30
fonte
1

Separa l'iterazione e l'elaborazione incapsulando l'iterazione.

L'iterazione su strutture multi-livello con cicli nidificati porta a applicazioni in cui gran parte del codice è in loop di rumore. Per elaborare tutti Level2Thing s in Level0Thing , sostituisci i tuoi cicli nidificati con questo:

for (Level2Thing t2: topThing.level2Things()) {
   // do something
}

dove level2Things() restituisce un Iterable<Level2Thing> .

Puoi trovare alcuni esempi di codice per incapsulare iterazioni nidificate qui .

    
risposta data 05.02.2013 - 18:56
fonte
-3

Per cicli molto annidati o flusso di codice complesso, spesso dichiaro anonimo Runnable s. Sebbene non sia direttamente correlato alla domanda, è comunque pertinente. Sono sicuro che c'è un esempio migliore di questo, ma è un inizio.

public int ComplexFunction() {
    final Integer value = new Integer();
    final Boolean quit = new Boolean(false);

    final Runnable doTest = new Runnable() {
        public void run() {
            if (value.intVal() > 100) {
                quit = new Boolean(true);
            }
        }
    }


    while (true) {
        value = new Integer(value.intVal() + 5);
        doTest.run();
        if (quit.booleanVal() == true) {
            return 1;
        }
    }
    return 0;
}
    
risposta data 10.09.2014 - 20:18
fonte

Leggi altre domande sui tag