Sentencias de control de flujo

Sentencia while

El programa de cuenta de caracteres usa un bucle while para contar los caracteres de la entrada:
class Count {
    public static void main(String[] args)
        throws java.io.IOException
    {
        int cuenta = 0;

        while (System.in.read() != -1)
            cuenta++;
        System.out.println("La entrada tiene " + cuenta + " caracteres.");
    }
}    
Una sentencia while realiza una acción mientras que una condición dada es cierta.

La sintáxis de la sentencia while es la siguiente:

while (expresión)
    sentencia
Mientras que expresión se evalúa a true, se realiza sentencia.

sentencia puede ser una única sentencia o un bloque de sentencias (una seucesión de sentencias encerradas entre llaves ('{' and '}'). Por ejemplo:

. . .
while (System.in.read() != -1) {
    cuenta++;
    System.out.println("Leído el carácter número: " + cuenta);
}
. . .
Java dispone de varias sentencias de control de flujo además de while:
   Sentencia             Palabra clave
Decisión           if-else, switch-case
bucle              for, while, do-while
excepción          try-catch-finally, throw
miscelláneas       break, continue, label:, return

Sentencia if-else

La sentencia if-else permite ejecutar sentencias (o bloques de sentencias) de forma selectiva basada en un criterio (evaluación de una expresión lógica).

Podemos escribir código que ejecute una sentencia de depuración si la variable de depuración está activada.

. . .
if (DEPURA)
    System.out.println("DEPURA: x = " + x);
. . .
O bien código que realice una acción si la variable respuesta es OK y otra distinta si no lo es:
    . . .
if (respuesta == OK) {
    . . .
    // código de la acción de OK
    . . .
} else {
    . . .
    // código de la acción de CANCEL
    . . .
}
int puntuacion;
String nota;

if (puntuacion >= 9) {
    nota = "Sobresaliente";
} else if (puntuacion >= 7) {
    nota = "Notable";
} else if (puntuacion >= 5) {
    nota = "Aprobado";
} else 
    nota = "Suspenso";
}
Únicamente se ejecuta la primera de las condiciones que se evalúa a cierta, y en caso de que ninguna se cumpla, se ejecuta la guardada por el else (8.5= "Suspenso"????).

Sentencia switch

Útil para casos en los que se quiere examinar varias posibilidades distintas de evaluación de una misma expresión. Ejemplo:
int mes;
. . .
switch (mes) {
case 1:  System.out.println("Enero"); break;
case 2:  System.out.println("Febrero"); break;
case 3:  System.out.println("Marzo"); break;
case 4:  System.out.println("Abril"); break;
case 5:  System.out.println("Mayo"); break;
case 6:  System.out.println("Junio"); break;
case 7:  System.out.println("Julio"); break;
case 8:  System.out.println("Agosto"); break;
case 9:  System.out.println("Septiembre"); break;
case 10: System.out.println("Octubre"); break;
case 11: System.out.println("Noviembre"); break;
case 12: System.out.println("Diciembre"); break;
}
Se puede expresar lo mismo utilizando la sentencia if-else?

Cada sentencia case debe ser única y el valor de cada case del mismo tipo que el devuelto por la expresión del switch.

Las sentencias break hacen que la ejecución del programa pase a la siguiente sentencia al switch.

A veces resulta conveniente usar sentencias case sin break:

int mes;
int numDías;
. . .
switch (mes) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
    numDías = 31;
    break;
case 4:
case 6:
case 9:
case 11:
    numDías = 30;
    break;
case 2:
    if ( ((año % 4 == 0) && !(año % 100 == 0)) || (año % 400 == 0) )
        numDías = 29;
    else
        numDías = 28;
    break;
}
Puede usarse una sentencia default al final de un switch para manejar todos los casos no cubiertos por ninguno de los case:
int mes;
. . .
switch (mes) {
case 1:  System.out.println("Enero"); break;
case 2:  System.out.println("Febrero"); break;
case 3:  System.out.println("Marzo"); break;
case 4:  System.out.println("Abril"); break;
case 5:  System.out.println("Mayo"); break;
case 6:  System.out.println("Junio"); break;
case 7:  System.out.println("Julio"); break;
case 8:  System.out.println("Agosto"); break;
case 9:  System.out.println("Septiembre"); break;
case 10: System.out.println("Octubre"); break;
case 11: System.out.println("Noviembre"); break;
case 12: System.out.println("Diciembre"); break;
default: System.out.println("¡No hay más meses!");
    break;
}

Otros bucles

Además de la sentencia while introducida anteriormente, hay dos construcciones para construir iteraciones: bucles for y bucles do-while.

El bucle for se debe usar cuando se conocen los límites y el incremento del bucle de antemano, como por ejemplo inspecciones de arrays, Strings, etc.

// siendo a una matriz de cualquier tipo
. . .
int length = a.length;
for (int i = 0, anterior= 0; i < length; i++) { 
    b[i]= anterior;
    anterior= a[i];
}

Sintáxis:
for (initialización; terminación; incremento)
    sentencia
initialización, terminación e incremento pueden aparecer o no. Por ejemplo un bucle que se ejecuta siempre y no hace nada:
for (;;);

Para los bucles que se van a ejecutar al menos una vez se suele utilizar la construcción do-while, en la que la expresión de finalización se evalúa al final del bucle:

do {
    sentencias
} while (expBooleana);
Un ejemplo típico de utilización de estos bucles es la lectura de un fichero, en que sabemos que al menos vamos a leer un carácter:
int c;
InputStream in;
. . .
do {
    c = in.read();
    . . .
} while (c != -1);

Sentencias de manejo de excepciones

Si un método a llama a un método b y al ejecutarse b ocurre un error, b puede lanzar una excepción para indicar el error al método a. Asimismo puede indicar cual fue el error utilizando la sentencia throw. El método a puede usar las sentencias try, catch, and finally para capturar y manejar la situación de error. Estas sentencias implican una alteración del flujo normal de control de un programa.

Sentencias de ramificación (branching)

La sentencia break hacía que el control del programa saltara a la sentencia inmediatamente posterior a la sentencia switch.

Hay otra forma de sentencia break que hace que el control pase a una sentencia etiquetada con un cierto identificador:

break saltaAquí;
...
// estas sentencias nunca se ejecutan
...
saltaAquí: Sentencia
Labeled breaks are an alternative to the goto statement which is not supported by the Java language.

La sentencia continue se puede usar dentro de un bucle para saltar hacia atrás, al principio del bucle, o bien para ir a una sentencia etiquetada. Por ejemplo:

public int indexOf(String strOrig, String strDest, int fromIndex) {
    char [] v1= new char[strOrig.length()];
    char [] v2= new char[strDest.length()];

    strOrig.getChars(0,strOrig.length()-1,v1,0);
    strDest.getChars(0,strDest.length()-1,v2,0);

    int max= v1.length-v2.length;

  test:
    for (int i = (fromIndex < 0) ? 0 : fromIndex; i <= max ; i++) {
      int n = v2.length;
      int j = i;
      int k = 0;
      while (n-- != 0) {
	if (v1[j++] != v2[k++]) {
	  continue test;
	}
      }    
      return i;
    }
    return -1;
  }

Nota: La sentencia continue sólo puede ser llamada desde dentro de un bucle.

Finalmente la última de las sentencias de ramificación de Java: return. return se usa para salir del método actual y devolver el control al método que nos había llamado, al punto donde se encuentra la llamada original al método.

La sentencia return devuelve un valor del tipo declarado en el método (o ninguno en caso de que el método se declare de tipo void)