Torres de Hanoi en Java

La leyenda.
En una antigua ciudad en la India, los monjes en un templo tienen que mover una pila de 64 discos sagrados de un lugar a otro.
Los discos son frágiles; sólo pueden ser cargados de uno en uno.
Un disco no debe nunca ser colocado arriba de otro más pequeño.
Además, solamente hay un lugar en el templo (aparte del lugar original y el lugar destino) suficientemente sagrado para poner una pila de discos allí y servir así de apoyo en el traslado de discos desde el origen hasta el destino.
Así que los monjes empiezan moviendo discos atrás y adelante, entre la pila original, la pila en el nuevo lugar de destino, y el lugar intermedio, siempre dejando las pilas en orden(el mayor en la base, el menor en la cima).
La leyenda dice además, que antes de que los monjes realicen el último movimiento para completar la torre en su nuevo lugar, el templo se reducirá a cenizas y el mundo se acabará.
Quizás esta leyenda tenga razón debido a la enorme cantidad de movimientos necesarios para cambiar de lugar los 64 discos
(2^64-1 = 18,446,744,073,709,551,615 movimientos).

Torres de Hanoi
 
Es un juego oriental que consta de tres columnas llamadas origen, destino y auxiliar y una serie de discos de distintos tamaños. Los discos están colocados de mayor a menor tamaño en la columna origen. El juego consiste en pasar todos los discos a la columna destino y dejarlos como estaban de mayor a menor. (el más grande en la base, el más pequeño arriba)
Las reglas del juego son las siguientes:
·         Sólo se puede mover un disco cada vez.
·         Para cambiar los discos de lugar se pueden usar las tres columnas.
·         Nunca deberá quedar un disco grande sobre un disco pequeño.
El problema de las torres de Hanoi se puede resolver de forma muy sencilla usando la recursividad y la técnica divide y vencerás. Para ello basta con observar que si sólo hay un disco (caso base), entonces se lleva directamente de la varilla origen a la varilla destino. Si hay que llevar n>1 (caso general) discos desde origen a destino entonces:

Se llevan n-1 discos de la varilla origen a la auxiliar.
Se lleva un solo disco (el que queda) de la varilla origen a la destino
Se traen los n-1 discos de la varilla auxiliar a la destino.




Utilizando recursividad se obtiene una solución muy simple pero que sorprendentemente funciona:
import java.util.*;
public class Hanoi {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n;
        System.out.println("Numero de discos: ");
        n = sc.nextInt();
        Hanoi(n,1,2,3);  //1:origen  2:auxiliar 3:destino                                                         
    }


    //Método Torres de Hanoi Recursivo
    public static void Hanoi(int n, int origen,  int auxiliar, int destino){
        if(n==1){
           System.out.println("mover disco de " + origen + " a " + destino);
        }else{
           Hanoi(n-1, origen, destino, auxiliar);
           System.out.println("mover disco de "+ origen + " a " + destino);
           Hanoi(n-1, auxiliar, origen, destino);
        }
    }
}
Ejercicios
1. Ejecuta el método anterior para distinto número de discos.
 
2. Se trata de realizar una modificación del método Torres de Hanoi. Escribe un método recursivo que calcule el número de movimientos necesarios para mover n discos de la torre origen a la torre destino.

Recursividad en Java

La recursividad es una técnica potente de programación que puede utilizarse en lugar de la iteración para resolver determinados tipos de problemas.
Por ejemplo, para escribir un método que calcule el factorial de un número entero no negativo, podemos hacerlo a partir de la definición de factorial:
Si n = 0 entonces
0! = 1
si n>0 entonces
n! = n * (n–1) * (n–2) * ... * 3 * 2 * 1 


Esto dará lugar a una solución iterativa en Java mediante un bucle for:
// Método Java no recursivo para calcular el factorial de un número
public double factorial(int n){
    double fact=1;
    int i;
    if (n==0){
        fact=1;
    }else{
        for(i=1;i<=n;i++){                                                                                        
            fact=fact*i;
        }
    }
    return fact;
}
Pero existe otra definición de factorial en función de sí misma:
0! = 1
n! = n · (n – 1)! ,    si n > 0   (El factorial de n es n por el factorial de n-1)
Esta definición da lugar a una solución recursiva del factorial en Java:
// Método Java recursivo para calcular el factorial de un número
public double factorial(int n){
    if (n==0){
        return 1;
    }else{
        return n*(factorial(n-1));                                                                                
    }
}

Un método es recursivo cuando entre sus instrucciones se encuentra una llamada a sí mismo.
La solución iterativa es fácil de entender. Utiliza una variable para acumular los productos y obtener la solución. En la solución recursiva se realizan llamadas al propio método con valores de n cada vez más pequeños para resolver el problema.
Cada vez que se produce una nueva llamada al método se crean en memoria de nuevo las variables y comienza la ejecución del nuevo método.
Para entender el funcionamiento de la recursividad, podemos pensar que cada llamada supone hacerlo a un método diferente, copia del original, que se ejecuta y devuelve el resultado a quien lo llamó.
En la figura siguiente podemos ver como sería la ejecución del programa Java anterior para calcular el factorial de 3. 
 



Un método recursivo debe contener:
  •      Uno o más casos base: casos para los que existe una solución directa.
  •      Una o más llamadas recursivas: casos en los que se llama sí mismo
Caso base: Siempre ha de existir uno o más casos en los que los valores de los parámetros de entrada permitan al método devolver un resultado directo. Estos casos también se conocen como solución trivial del problema.
En el ejemplo del factorial el caso base es la condición:
if (n==0)
     return 1;
si n=0 el resultado directo es 1    No se produce llamada recursiva

Llamada recursiva: Si los valores de los parámetros de entrada no cumplen la condición del caso base se llama recursivamente al método. En las llamadas recursivas el valor del parámetro en la llamada se ha de modificar de forma que se aproxime cada vez más hasta alcanzar al valor del caso base.
En el ejemplo del factorial en cada llamada recursiva se utiliza n-1
return n * ( factorial(n-1) );
por lo que en cada llamada el valor de n se acerca más a 0 que es el caso base.

La recursividad es especialmente apropiada cuando el problema a resolver (por ejemplo calculo del factorial de un número) o la estructura de datos a procesar (por ejemplo los árboles) tienen una clara definición recursiva.
No se debe utilizar la recursión cuando la iteración ofrece una solución obvia. Cuando el problema se pueda definir mejor de una forma recursiva que iterativa lo resolveremos utilizando recursividad.
Para medir la eficacia de un algoritmo recursivo se tienen en cuenta tres factores:
  • Tiempo de ejecución
  • Uso de memoria
  • Legibilidad y facilidad de comprensión
Las soluciones recursivas suelen ser más lentas que las iterativas por el tiempo empleado en la gestión de las sucesivas llamadas a los métodos. Además consumen más memoria ya que se deben guardar los contextos de ejecución de cada método que se llama.

A pesar de estos inconvenientes, en ciertos problemas, la recursividad conduce a soluciones que son mucho más fáciles de leer y comprender que su correspondiente solución iterativa. En estos casos una mayor claridad del algoritmo puede compensar el coste en tiempo y en ocupación de memoria.

De todas maneras, numerosos problemas son difíciles de resolver con soluciones iterativas, y sólo la solución recursiva conduce a la resolución del problema (por ejemplo, Torres de Hanoi o recorrido de Árboles).


Ejemplos de Recursividad

Paso de parámetros en Java y ámbito de las variables

1. PARÁMETROS ACTUALES Y FORMALES
Parámetros actuales: Son los argumentos que aparecen en la llamada a un método. Contienen los valores que se le pasan al método. Un parámetro actual puede ser una variable, un objeto, un valor literal válido, etc.
Parámetros formales: Son los argumentos que aparecen en la cabecera del método. Reciben los valores que se envían en la llamada al método. Se utilizan como variables normales dentro del método.
Los parámetros actuales y los formales deben coincidir en número, orden y tipo. Si el tipo de un parámetro actual no coincide con su correspondiente parámetro formal, el sistema lo convertirá al tipo de este último, siempre que se trate de tipos compatibles. Si no es posible la conversión, el compilador dará los mensajes de error correspondientes.
Si el método devuelve un valor, la llamada al método puede estar incluida en una expresión que recoja el valor devuelto.
2. ÁMBITO DE UNA VARIABLE
El ámbito o alcance de una variable es la zona del programa donde la variable es accesible.
El ámbito lo determina el lugar donde se declara la variable.
En Java las variables se pueden clasificar según su ámbito en:
- Variables miembro de una clase o atributos de una clase
- Variables locales
- Variables de bloque
Variables miembro o atributos de una clase
Son las declaradas dentro de una clase y fuera de cualquier método.
Aunque suelen declararse al principio de la clase, se pueden declarar en cualquier lugar siempre que sea fuera de un método.
Son accesibles en cualquier método de la clase.
Pueden ser inicializadas.
Si no se les asigna un valor inicial, el compilador les asigna uno por defecto:
- 0 para las numéricas
- '\0' para las de tipo char
- null para String y resto de referencias a objetos.
Variables locales
Son las declaradas dentro de un método.
Su ámbito comienza en el punto donde se declara la variable.
Están disponibles desde su declaración hasta el final del método donde se declaran.
No son visibles desde otros métodos.
Distintos métodos de la clase pueden contener variables con el mismo nombre. Se trata de variables distintas.
El nombre de una variable local debe ser único dentro de su ámbito.
Si se declara una variable local con el mismo nombre que una variable miembro de la clase, la variable local oculta a la miembro. La variable miembro queda inaccesible en el ámbito de la variable local con el mismo nombre.
Se crean en memoria cuando se declaran y se destruyen cuando acaba la ejecución del método.
No tienen un valor inicial por defecto. El programador es el encargado de asignarles valores iniciales válidos.
Los parámetros formales son variables locales al método.
Variables de bloque
Son las declaradas dentro de un bloque de instrucciones delimitado por llaves { }.
Su ámbito comienza en el punto donde se declara la variable.
Están disponibles desde su declaración hasta el final del bloque donde se declaran.
No son visibles desde otros bloques.
Distintos bloques pueden contener variables con el mismo nombre. Se trata de variables distintas.
Si un bloque de instrucciones contiene dentro otro bloque de instrucciones, en el bloque interior no se puede declarar una variable con el mismo nombre que otra del bloque exterior.
Se crean en memoria cuando se declaran y se destruyen cuando acaba la ejecución del bloque.
No tienen un valor inicial por defecto. El programador es el encargado de asignarles valores iniciales válidos.
Ejemplo de variables de bloque en java:


Un ejemplo típico de declaración de variables dentro de un bloque es hacerlo en las instrucciones for:
for(int i = 1; i<=20; i+=2){
      System.out.println(i);
}
La variable i se ha declarado dentro del for y solo es accesible dentro de él.
Si a continuación de la llave final del for escribimos:
System.out.println(i);
se producirá un error de compilación: la variable i no existe fuera del for y el compilador nos dirá que no está declarada.

En el siguiente ejemplo se declara la variable x en cada bloque for:
public static void main(String[] args) {
    int suma = 0;
    for (int x = 1; x <= 10; x++) {
          suma = suma + x;
    }
    for (int x = 1; x <= 10; x++) {
        suma = suma + x * x;
    }
    System.out.println(suma);
}
Las variables locales deben tener nombres únicos dentro de su alcance.
Ejemplo de solapamiento de variables locales y de bloque que producen un error de compilación:
public static int sumaCuadrados(int n) {
    int suma = 0;
    for (int i = 1; i <= n; i++) {
          int n = i * i; // ERROR n ya declarada
          suma = suma + n;
     }
     return suma;
}
3. PASO DE PARÁMETROS EN JAVA
En programación hay dos formas de paso de parámetros a un método:
Paso de parámetros por valor
Cuando se invoca al método se crea una nueva variable (el parámetro formal) y se le copia el valor del parámetro actual.
El parámetro actual y el formal son dos variables distintas aunque tengan el mismo nombre.
El método trabaja con la copia de la variable por lo que cualquier modificación que se realice sobre ella dentro del método no afectará al valor de la variable fuera.
En definitiva, el método no puede modificar el valor de la variable original.
Paso de parámetros por referencia
Cuando se invoca al método se crea una nueva variable (el parámetro formal) a la que se le asigna la dirección de memoria donde se encuentra el parámetro actual.
En este caso el método trabaja con la variable original por lo que puede modificar su valor.
Lenguajes como C, C++, C#, php, VisualBasic, etc. soportan ambas formas de paso de parámetros.
Pero, cómo se realiza el paso de parámetros en Java?
En Java todos los parámetros se pasan por valor
Cuando se realiza la llamada a un método, los parámetros formales reservan un espacio en memoria y reciben los valores de los parámetros actuales.
Cuando el argumento es de tipo primitivo (int, double, char, boolean, float, short, byte), el paso por valor significa que cuando se invoca al método se reserva un nuevo espacio en memoria para el parámetro formal. El método no puede modificar el parámetro actual.
Cuando el argumento es una referencia a un objeto (por ejemplo, un array o cualquier otro objeto) el paso por valor significa que el método recibe una copia de la dirección de memoria donde se encuentra el objeto. La referencia no puede modificarse pero sí se pueden modificar los contenidos de los objetos durante la ejecución del método.
Tipos primitivos: no se pueden modificar
Arrays y objetos: se pueden modificar
Ejemplo de paso de parámetros por valor. La variable n no se modifica.
public static void main(String[] args) {
   int n = 1;
  System.out.println("Valor de n en main antes de llamar al método:" + n);
 incrementar(n);
 System.out.println("Valor de n en main después de llamar al método:" + n);
}

public static void incrementar(int n){
      n++;
     System.out.println("Valor de n en el método después incrementar:" + n);
}
La salida de este programa es:
Valor de n en main antes de llamar al método: 1
Valor de n en el método después incrementar: 2
Valor de n en main después de llamar al método: 1
Si es necesario que un método modifique un tipo primitivo que recibe como parámetro podemos utilizar un array auxiliar.
Cuando se pasa un array a un método se pasa la dirección de memoria donde se encuentra por lo tanto el método puede modificarlo.
public static void main(String[] args) {
 int n = 1;
 int [] aux = new int[1]; //aux: array auxiliar para el paso de parámetros
 System.out.println("Valor de n en main antes de llamar al método: " + n);
   aux[0]=n;
   incrementar(aux);
   n = aux[0];
   System.out.println("Valor de n en main después de llamar al método: " 
                                                                                             + n);
}
public static void incrementar(int [] x){
  x[0]++;
 System.out.println("Valor de n en el método después incrementar: " 
                                                                                            + x[0]);
}
La salida de este programa es:
Valor de n en main antes de llamar al método: 1
Valor de n en el método después incrementar: 2
Valor de n en main después de llamar al método: 2

Métodos en Java


Un método en Java es un conjunto de instrucciones definidas dentro de una clase, que realizan una determinada tarea y a las que podemos invocar mediante un nombre.

Algunos métodos que hemos utilizado hasta ahora:
  • Math.pow()
  • Math.sqrt()
  • Character.isDigit()
  • System.out.println();
En la imagen vemos la llamada al método Math.pow para que realice la operación de elevar 3 a 7. También en la instrucción siguiente se está haciendo uso del método println para mostrar el valor de x.

Cuando se llama a un método, la ejecución del programa pasa al método y cuando éste acaba, la ejecución continúa a partir del punto donde se produjo la llamada.

En la imagen se muestra el flujo de ejecución del programa cuando se produce la llamada al método Math.pow: En la llamada al método le enviamos los valores con los que tiene que realizar la operación. La ejecución del programa continúa dentro del método. Su tarea en este caso es realizar la operación de elevar 3 a 7. Cuando termina devuelve el resultado al punto donde se invocó el método. La ejecución continúa en el método main desde el punto donde se produjo la llamada. 
Utilizando métodos:
  • Podemos construir programas modulares.
  • Se consigue la reutilización de código. En lugar de escribir el mismo código repetido cuando se necesite, por ejemplo para validar una fecha, se hace una llamada al método que lo realiza.
Cuando trabajamos con métodos debemos tener en cuenta lo siguiente:
  • En Java un método siempre pertenece a una clase. No podemos escribir métodos fuera de una clase.
  • No podemos escribir métodos dentro de otros métodos.
  • Todo programa java tiene un método llamado main. La ejecución del programa empieza en este método. El método main es el punto de entrada al programa y también el punto de salida.
  • Un método tiene un único punto de inicio, representando por la llava de inicio {
  • La ejecución de un método termina cuando se llega a la llave final } o cuando se ejecuta una instrucción return.
  • La instrucción return puede aparecer en cualquier lugar dentro del método, no tiene que estar necesariamente al final. 
  • Cuando un método finaliza, la ejecución del programa continúa a partir del punto donde se produjo la llamada al método. 
  • Desde dentro de un método se puede a su vez invocar a otro método.


1. ESTRUCTURA GENERAL DE UN MÉTODO JAVA
La estructura general de un método Java es la siguiente:
[especificadores] tipoDevuelto nombreMetodo([lista parámetros]) [throws listaExcepciones]          
{
    // instrucciones
   [return valor;]
}
Los elementos que aparecen entre corchetes son opcionales.

especificadores (opcional): determinan el tipo de acceso al método. Se verán en detalle más adelante.

tipoDevuelto: indica el tipo del valor que devuelve el método. En Java es imprescindible que en la declaración de un método, se indique el tipo de dato que ha de devolver. El dato se devuelve mediante la instrucción return. Si el método no devuelve ningún valor este tipo será void.
nombreMetodo: es el nombre que se le da al método. Para crearlo hay que seguir las mismas normas que para crear nombres de variables.
Lista de parámetros (opcional): después del nombre del método y siempre entre paréntesis puede aparecer una lista de parámetros, también llamados argumentos, separados por comas. Estos parámetros son los datos de entrada que recibe el método para operar con ellos. Un método puede recibir cero o más argumentos. Se debe especificar para cada argumento su tipo. Los paréntesis a continuación del nombre del método son obligatorios aunque estén vacíos.
throws listaExcepciones (opcional): indica las excepciones que puede generar y manipular el método.
return: se utiliza para devolver un valor. Algunos aspectos importantes sobre la palabra clave return en un método:

  • La palabra clave return va seguida de una expresión que será evaluada para saber el valor de retorno. Esta expresión puede ser compleja o puede ser simplemente una variable de tipo primitivo o una constante.
  • El tipo del valor de retorno debe coincidir con el tipoDevuelto que se ha indicado en la declaración del método.
  • Si el método no devuelve nada (tipoDevuelto = void) la instrucción return es opcional.
  • Un método puede devolver un tipo primitivo, un array, un String o un objeto.
  • La instrucción return puede aparecer en cualquier lugar dentro del método.
  • La ejecución de un método termina cuando se llega a su llave final } o cuando se ejecuta la instrucción return.
2. IMPLEMENTACIÓN DE MÉTODOS EN JAVA
Pasos para implementar un método:
1.     Describir lo que el método debe hacer.
2.     Determinar las entradas del método, es decir, lo que el método recibe.
3.     Determinar los tipos de datos de las entradas.
4.     Determinar lo que debe devolver el método y el tipo del valor devuelto.
5.     Escribir las instrucciones que forman el cuerpo del método.
6.     Prueba del método: diseñar distintos casos de prueba.
Ejemplo de método: método llamado sumar que recibe dos números enteros y calcula y devuelve su suma.
import java.util.Scanner;

public class Metodos1 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int numero1, numero2, resultado;
        System.out.print("Introduce primer número: ");                                             
        numero1 = sc.nextInt();
        System.out.print("Introduce segundo número: ");
        numero2 = sc.nextInt();
        resultado = sumar(numero1, numero2);
        System.out.println("Suma: " + resultado);
    }

    //método sumar
    public static int sumar(int a, int b){
           int c;
           c = a + b;
           return c;
    }

}

El método se llama sumar. Recibe dos números enteros a y b que son los parámetros de entrada. El método devuelve un valor de tipo int.


El flujo de ejecución del programa es el siguiente:
  1. En el método main cuando se produce la llamada al método sumar, los valores de las variables numero1 y numero2 se copian en las variables a y b respectivamente. Las variabels a y b son los parámetros del método. 
  2. El flujo de ejecución del programa pasa al método sumar.
  3. El método suma los dos números y guarda el resultado en c. 
  4. El método devuelve mediante la instrucción return la suma calculada.
  5. Finaliza la ejecución del método.
  6. El flujo de ejecución del programa continúa en el método main a partir de dónde se produjo la llamada al método sumar.
  7. El valor devuelto por el método es lo que se asigna a la variable resultado en el método main
Si un método devuelve un valor, como sucede en el método sumar, la llamada al método puede estar incluida en una expresión que utilice el valor devuelto.
En el ejemplo anterior, el método sumar devuelve un valor entero que después vamos a mostrar. En este caso podríamos haber hecho la llamada al método directamemte dentro del System.out.println:
System.out.println("Suma: " + sumar(numero1, numero2));
Ejemplo de programa Java que contiene un método con varios return:
Programa que lee por teclado un año y calcula y muestra si es bisiesto. Para realizar el cálculo se utiliza un método llamado esBisiesto.
El método esBisiesto tiene un parámetro de tipo entero llamado a. Será el encargado de recibir el valor del año a comprobar si es bisiesto o no. El método devuelve un valor de tipo boolean. Devuelve true si el año recibido es bisiesto y false si no lo es.
Como el método devuelve un dato de tipo boolean se puede llamar dentro de una instrucción if. 
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int año;
        System.out.print("Introduce año: ");
        año = sc.nextInt();
        if(esBisiesto(año)){  //llamada al método
           System.out.println("Bisiesto");
        }else{
           System.out.println("No es bisiesto");
        }
    }

    /*
     * método que calcula si un año es o no bisiesto                                               
     */     
    public static boolean esBisiesto(int a){    
        if(a%4==0 && a%100!=0 || a%400==0)
           return true;
        else
           return false;
    }

}
Flujo de ejecución:
  1. En el método main se llama al método esBisiesto dentro de la instrucción if.
  2. El valor de la variable año se copia en la variable a.
  3. El flujo de ejecución pasa al método esBisiesto.
  4. El método comprueba si el año recibido es o no bisiesto.
  5. El método devuelve true si el año es bisiesto o false si no lo es.
  6. Finaliza la ejecución del método.
  7. El flujo de ejecución continúa en el método main en la instrucción if donde se produjo la llamada al método.
  8. El valor true o false devuelto por el método es lo que determina si la condición es cierta o no.

Ejemplo de programa Java: Método que no devuelve ningún valor. 
El método cajaTexto tiene un parámetro de tipo String. 
El String que recibe lo muestra por pantalla rodeado con un borde.
Este método no devuelve nada, solo se limita a mostrar el String por pantalla.
Cuando un método no devuelve nada hay que indicar void como tipo devuelto.
Como el métono no devuelve nada no es necesario escribir la sentencia return.
El método acaba cuando se alcanza la llave final.

import java.util.Scanner;

public class MetodoVoid {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String cadena;
        System.out.print("Introduce cadena de texto: ");
        cadena = sc.nextLine();
        cajaTexto(cadena); //llamada al método
    }

    // método que muestra un String rodeado por un borde 
    public static void cajaTexto(String str){
            int n = str.length(); //longitud del String
            for (int i = 1; i <= n + 4; i++){ //borde de arriba
                 System.out.print("#"); 
            }
            System.out.println();
            System.out.println("# " + str + " #"); //cadena con un borde en cada lado              
            for (int i = 1; i <= n + 4; i++){ //borde de abajo
                 System.out.print("#"); 
            }
            System.out.println();
    }

}

Estructuras de control en Java

Las estructuras de control determinan la secuencia de ejecución de las sentencias de un programa. 

Los programas contienen instrucciones que se ejecutan generalmente una a continuación de la otra según la secuencia en la que el programador ha escrito el código.  Sin embargo, hay ocasiones en las que es necesario romper esta secuencia de ejecución para hacer que una serie de instrucciones se ejecuten o no dependiendo de una determinada condición o hacer que una serie de instrucciones se repitan un número determinado de veces.

Las estructuras de control permiten modificar el orden natural de ejecución de un programa. Mediante ellas podemos conseguir que el flujo de ejecución de las instrucciones sea el natural o varíe según se cumpla o no una condición o que un bloque de instrucciones se repitan dependiendo de que una condición se cumpla o no. 
Las estructuras de control tienen las siguientes características:
  • Tienen un único punto de entrada y un único punto de salida. 
  • Están compuestas por instrucciones o por otras estructuras de control.
Las estructuras de control se dividen en las siguientes categorías:
  • Estructura Secuencial
  • Estructura Condicional o Selectiva
  • Estructura Iterativa o Repetitiva.
  • Instrucciones de salto 
La siguiente imagen muestra todas las estructuras de control del lenguaje Java
 


1. ESTRUCTURA SECUENCIAL

Las instrucciones de un programa se ejecutan por defecto en orden secuencial. Esto significa que las instrucciones se ejecutan en secuencia, una después de otra, en el orden en que aparecen escritas dentro del programa.

La estructura secuencial es el orden natural de ejecución. Las instrucciones que componen esta estructura se ejecutan en orden una a continuación de la otra.

La mayoría de las instrucciones están separadas por el carácter punto y coma (;).
 
Las instrucciones se suelen agrupar en bloques.
El bloque de sentencias se define por el carácter llave de apertura ({) para marcar el inicio del mismo, y el carácter llave de cierre (}) para marcar el final.

Ejemplo de bloque de instrucciones:

{

int n = 1;

int m = 0;

m = n++ ;

System.out.println(m);

System.out.println(n);

}

Si el bloque de instrucciones está constituido por una única instrucción no es obligatorio el uso de las llaves de apertura y cierre  {  }, aunque es recomendable utilizarlas.

Ejemplo de programa Java con estructura secuencial: programa que lee dos números por teclado y los muestra por pantalla. En este caso hay un solo bloque de instrucciones contenidas entre las llaves de apertura y cierre del método main. Las instrucciones se ejecutan en el mismo orden que aparecen escritas.
/* 
   Programa que lee dos números por teclado y los muestra por pantalla.
*/
import java.util.*;
public class Secuencial {

    public static void main(String[] args){ //--> inicio del método main
	
        //declaración de variables
        int n1, n2;
        Scanner sc = new Scanner(System.in);
        //leer el primer número 
        System.out.println("Introduce un número entero: ");                                                       
        n1 = sc.nextInt();      //lee un entero por teclado
        //leer el segundo número
        System.out.println("Introduce otro número entero: "); 
        n2 = sc.nextInt();      //lee un entero por teclado    
        //mostrar resultado
        System.out.println("Ha introducido los números: " + n1 + " y " + n2);                                     
		
    } //--> final del método main
}

Ejemplo de programa Java con estructura secuencial: programa que lee por teclado dos valores de tipo double y a continuación muestra su suma, resta y multiplicación. En este caso el programa también está formado por un único bloque de instrucciones que se ejecutan secuencialmente dentro del método main.
/*
 * Mostrar la suma, resta y multiplicación de dos valores
 * de tipo double que se introducen por teclado.
 */
import java.util.*;
public class Secuencial2  {
    public static void main(String[] args){
	
        Scanner sc = new Scanner(System.in);
        double numero1, numero2;
        System.out.println("Introduce el primer número:");                                                        
        numero1 = sc.nextDouble();
        System.out.println("Introduce el segundo número:");
        numero2 = sc.nextDouble();
        System.out.println("Números introducido: " + numero1 + "  " + numero2);
        System.out.println(numero1 + " + " + numero2 + " = " + (numero1+numero2));
        System.out.println(numero1 + " - " + numero2 + " = " + (numero1-numero2));
        System.out.println(numero1 + " * " + numero2 + " = " + numero1*numero2);                                  
		  
    }
}
Para modificar el orden de ejecución de las instrucciones de un programa Java se utilizan las estructuras condicionales y repetitivas.

2. ESTRUCTURA CONDICIONAL, ALTERNATIVA O SELECTIVA

Es una de las estructuras que permiten modificar el orden de ejecución de las instrucciones del programa.

Una estructura condicional determina si se ejecutan unas acciones u otras según se cumpla o no una determinada condición.
 
La condición que se comprueba para decidir si unas instrucciones se ejecutan o no debe ser una expresión booleana es decir debe dar como resultado un valor booleano true ó false.

En java la estructura condicional se implementa mediante:
  • Instrucción if.
  • Instrucción switch.
  • Operador condicional ? :
2.1 INSTRUCCION if

La instrucción condicional if puede ser de tres tipos::
  • Condicional simple: if
  • Condicional doble: if ... else ...
  • Condicional múltiple o if anidados: if .. else if ..
Estructura Condicional simple 
Como su nombre indica, es la estructura condicional más sencilla en Java. La usaremos para decidir si una instrucción o bloque de instrucciones se ejecuta o no dependiendo de una condición. Se evalúa la condición y si se cumple se ejecuta. Si no se cumple la condición, se salta dicho grupo de instrucciones.


Sintaxis:

   
instrucción 1;
instrucción 2;
if(condición){    //inicio de la condición
   instrucción 3;
   instrucción 4;
}                 //fin de la condición
instrucción 5;
instrucción 6;


 
 
 
 
 
 
En este caso se ejecutan las instrucciones 1 y 2 y a continuación se evalúa la condición. Si se cumple, se ejecutan las instrucciones 3 y 4 y a continuación la 5 y 6. Si la condición no se cumple, las instrucciones 3 y 4 no se ejecutan, siguiendo la ejecución del programa por las instrucciones 5 y 6.
Ejemplo de programa Java con estructura condicional: Programa que pide que se introduzca una nota por teclado y muestra dos mensajes si la nota es mayor o igual a 5.
/*
 * Programa que pide una nota por teclado y muestra dos mensajes si la nota es                                    
 * mayor o igual que 5
 */
import java.util.*;
public class CondicionalSimple1 {
    public static void main( String[] args ){
        Scanner sc = new Scanner( System.in );
        System.out.print("Nota: ");
        int nota = sc.nextInt();
        if (nota >= 5){//----------------------inicio de la condición                                             
            System.out.println("Enhorabuena!!");
            System.out.println("Has aprobado");
        }//-------------------------------------fin de la condición
        System.out.println("Hasta Pronto!");
    }
}
En este ejemplo si se introduce un número >= 5 el programa mostrará:
Enhorabuena!!     
Has aprobado
Hasta Pronto! 
Si introducimos un valor < 5 el programa mostrará:
Hasta Pronto! 
Si un bloque de instrucciones contiene una sola instrucción no es necesario escribir las llaves { } aunque para evitar confusiones se recomienda escribir las llaves siempre.
Supongamos que en el ejemplo anterior la instrucción if la escribimos así:
        if (nota >= 5){//----------------------inicio de la condición
            System.out.println("Enhorabuena!!");
        }//-------------------------------------fin de la condición
Como el bloque de instrucciones dentro del if ahora solo contiene una instrucción, las llaves se pueden omitir. En ese caso el programa quedaría así:
/*
 * Programa que pide una nota por teclado y muestra un mensaje si la nota es                                      
 * mayor o igual que 5
 */
import java.util.*;
public class CondicionalSimple1 {
    public static void main( String[] args ){                                                                     
        Scanner sc = new Scanner( System.in );
        System.out.print("Nota: ");
        int nota = sc.nextInt();
        if (nota >= 5)
            System.out.println("Enhorabuena!!");                                                                  
        System.out.println("Hasta Pronto!");
    }
}
Ahora si se introduce un número >= 5 el programa mostrará:
Enhorabuena!!
Hasta Pronto!
Si introducimos un valor < 5 mostrará:
Hasta Pronto!
No escribir las llaves en estos casos puede conducir a un código confuso de entender por lo que es siempre recomendable escribir las llaves incluso en los casos en los que no sea necesario.
Ten en cuenta que el código no es obligatorio escribirlo con ese formato en el que las instrucciones están tabuladas. Aunque no es un buen estilo de programación, se podría hacer escrito así:
if (nota >= 5)                                                                            
System.out.println("Enhorabuena!!");                                                                              
System.out.println("Hasta Pronto!");                                                                              
Escribiéndolo así puede llevar a confusion al no estar claro a simple vista donde comienza el bloque if y donde acaba. Por eso es recomendable escribir las llaves siempre.
 
Estructura Condicional Doble

Mediante esta estructura de control el flujo de ejecución del programa puede seguir dos caminos distintos dependiendo del valor de una condición.

Se evalúa la condición y si se cumple se ejecuta una determinada instrucción o grupo de instrucciones. Si no se cumple se ejecuta otra instrucción o grupo de instrucciones.
 

 
Sintaxis en Java:

         


En este caso se ejecutan las instrucciones 1 y 2 y a continuación se evalúa la condición. Si se cumple, se ejecutan las instrucciones 3 y 4. Si la condición no se cumple se ejecutan las instrucciones 5 y 6. En ambos casos el programa continuará su ejecución por las instrucciones 7 y 8.

Ejemplo: Programa que lee una nota por teclado y muestra un mensaje indicando si se ha aprobado o no. Si la nota es >= 5 mostrará los mensajes:
Enhorabuena!!     
Has aprobado
Si la nota es < 5 mostrará el mensaje: 
Lo siento, has suspendido   
/*
 * Programa que pide una nota por teclado y muestra si se ha aprobado o no
 */
import java.util.*;
public class EjemploIfElse {
    public static void main( String[] args ){                                                                     
        Scanner sc = new Scanner( System.in );
        System.out.print("Nota: ");
        int nota = sc.nextInt();
        if (nota >= 5){ 
            System.out.println("Enhorabuena!!");
            System.out.println("Has aprobado");
        } else {
            System.out.println("Lo siento, has suspendido");                                                      
        }
        System.out.println("Hasta Pronto!");
    }
}
Ejemplo: programa que lee un número entero por teclado y muestra un mensaje indicando si el número es par o impar.

/*
 * Programa que pide un número por teclado y muestra si es par o impar                                            
 */
import java.util.*;
public class EjemploIfElse2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num;
        System.out.print("Introduzca un número entero: ");                                                        
        num = sc.nextInt();
        if (num % 2 == 0) {
            System.out.println("PAR");
        } else {
            System.out.println("IMPAR");
        }
    }
}

Ejemplos de ejecución:

Ejemplo 1
Introduzca un número entero: 3     
IMPAR 
Ejemplo 2 
Introduzca un número entero: 214     
PAR
Estructura Condicional Múltiple: if anidados 

La estructura condicional múltiple se obtiene encadenando sentencias if ... else.

Mediante esta estructura podemos construir estructuras de selección más complejas.

Un ejemplo de if múltiple expresado en diagrama de flujo puede ser este:




Sintaxis en Java:
Cada else se corresponde con el if más próximo que no haya sido emparejado.
Una vez que se ejecuta un bloque de instrucciones, la ejecución continúa en la siguiente instrucción que aparezca después de estructura condicional múltiple.

Ejemplo de programa Java que contiene una estructura condicional múltiple: Programa que lee una hora (número entero) y muestra un mensaje según la hora introducida corresponda a la mañana, la tarde o la noche.
//Programa que muestra un saludo distinto según la hora introducida
import java.util.*;
public class EjemploIfAnidados {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int hora;
        System.out.print("Introduzca una hora (>= 0 y <= 23): ");                                                 
        hora = sc.nextInt();
        if (hora >= 0 && hora < 12) {
            System.out.println("Buenos días");
        } else if (hora >= 12 && hora < 21) {
            System.out.println("Buenas tardes");
        } else if (hora >= 21 && hora < 24) {
            System.out.println("Buenas noches");
        } else {
            System.out.println("Hora no válida");
        }
        System.out.println("Hasta pronto!!!");                                                                    
    }
}
Cuatro ejemplos de ejecución del programa:
Introduzca una hora (>= 0 y <= 23): 6   
Buenos días
Hasta pronto!!!
Introduzca una hora (>= 0 y <= 23): 21  
Buenas noches
Hasta pronto!!!
Introduzca una hora (>= 0 y <= 23): 25
Hora no válida
Hasta pronto!!!
Introduzca una hora (>= 0 y <= 23): 13
Buenas tardes
Hasta pronto!!!
En estos ejemplos podemos comprobar que una vez que se ejecuta una de las instrucciones dentro del bloque de if anidados, la ejecución del programa continúa en la siguiente instrucción a continuación del bloque de if anidados, en este caso la ejecución sigue por la instrucción
System.out.println("Hasta pronto!!!");
Ejemplo de programa Java que contiene una estructura condicional múltiple:

Programa que pide que se introduzca un valor numérico de tipo double correspondiente a la nota de un alumno en una determinada asignatura y muestra un texto con la calificación equivalente de la siguiente forma:

Si la nota es menor que 5 muestra “Suspenso”

Si la nota es mayor o igual que 5 y menor que 6 muestra “Suficiente”

Si la nota es mayor o igual que 6 y menor que 7 muestra “Bien”

Si la nota es mayor o igual que 7 y menor que 9 muestra “Notable”

Si la nota es mayor o igual que 9 y menor que 10 muestra “Sobresaliente”

Si la nota es igual a 10 muestra “Matrícula de honor”

Si la nota es menor que 0 o mayor que 10 mostrará el mensaje “Nota no válida”

// programa que lee una nota y escribe la calificación correspondiente
import java.util.*;
public class EjemploIfAnidados2 {
    public static void main(String[] args) {                                                                      
        Scanner sc = new Scanner(System.in);
        double nota;
        System.out.println("Introduzca una nota entre 0 y 10: ");
        nota = sc.nextDouble();
        System.out.println("La calificación del alumno es ");
        if (nota < 0 || nota > 10) {
            System.out.println("Nota no válida");
        } else if (nota == 10) {
            System.out.println("Matrícula de Honor");
        } else if (nota >= 9) {
            System.out.println("Sobresaliente");
        } else if (nota >= 7) {
            System.out.println("Notable");                                                                        
        } else if (nota >= 6) {
            System.out.println("Bien");
        } else if (nota >= 5) {
            System.out.println("Suficiente");
        } else {
            System.out.println("Suspenso");
        }
    }
}
Errores comunes que se suelen cometer en las instrucciones if

1. Escribir un punto y coma al final de la condición:

if (nota >= 6);

        System.out.println("Notable");

 

En este caso el mensaje "Notable" saldrá siempre. El if termina en el  ;

2. Escribir elseif en lugar de else if

elseif (nota >= 5)

        System.out.println("Suficiente");

3. Usar = en lugar de   ==   en las comparaciones

if (nota=10)

    System.out.println("Matrícula de Honor");

4. Errores al comparar dos String

No se deben usar los operadores relacionales ==, >, <, <= , etc.

if(cadena1 == cadena2){ //Comparación no válida de 2 String

Comparar dos String en java 

Para comprobar si dos String son iguales se debe usar el método equals:

if (cadena1.equals(cadena2))

Si lo que queremos es comprobar si dos cadenas son iguales sin tener en cuenta mayúscula o minúscula se usa el método equalsIgnoreCase:

if (cadena1.equalsIgnoreCase(cadena2))

Para comparar dos cadenas en el orden alfabético se usa el método compareTo

El método compareTo compara las dos cadenas alfabéticamente y devuelve un valor entero con el resultado de la comparación de la siguiente forma:

  • Devuelve 0 si las dos cadenas son iguales.
  • Devuelve un valor < 0 si la primera cadena es alfabéticamente menor que la segunda.
  • Devuelve un valor > 0 si la primera cadena es alfabéticamente mayor que la segunda.

Ejemplos de uso:

Suponiendo que cadena1 y cadena2 son de tipo String y ambas contienen una cadena de caracteres, podemos compararlas de varias formas según necesitemos:

if(cadena1.compareTo(cadena2) < 0) //si la condición se cumple significa que

                                   //cadena1 es alfabéticamente menor que cadena2

if(cadena1.compareTo(cadena2) > 0) //si la condición se cumple significa que

                                   //cadena1 es alfabéticamente mayor que cadena2

if(cadena1.compareTo(cadena2) == 0)  //si la condición se cumple significa que

                                     //cadena1 es igual que cadena2

if(cadena2.compareTo(cadena1) > 0)  //si la condición se cumple significa que

                                    //cadena2 es alfabéticamente mayor que cadena1

if(cadena2.compareTo(cadena1) < 0)  //si la condición se cumple significa que

                                    //cadena2 es alfabéticamente menor que cadena1

Para comparar Strings en el orden alfabético sin tener en cuenta mayúsculas o minúsculas se usa el método compareToIgnoreCase

if(cadena1.compareToIgnoreCase(cadena2) > 0) 

En este saso, si la condición se cumple significa que cadena 1 es alfabéticamente mayor que cadena2  sin importar que los caracteres en ambas cadenas estén en mayúsculas o en minúsculas.

2.2 INSTRUCCION switch

Esta estructura de control se utiliza para seleccionar una de entre múltiples opciones posibles. Es una alternativa a los if .. else anidados. Si el número de anidamientos if .. else es elevado, la estructura switch produce un código más sencillo de leer y modificar.

El flujo de ejecución del programa lo determina el valor de una variable o expresión.

El tipo de esta variable o expresión puede ser uno de los siguientes:

  • Tipo primitivo: byte, short, char, int.
  • La clase envolvente de los tipos primitivos anteriores: Byte, Short, Character, Integer.
  • Tipo String.
  • Tipos enumerados (enum). 

La instrucción switch no permite que la variable o expresión sea del tipo float o double.

La sintaxis general de una estructura switch es la siguiente:

switch (expresión){

case VALOR1:

           instrucciones1;

           break;

case VALOR2:

           instrucciones2;

           break;

.....

default:

           instrucciones3;

}

Funcionamiento de la instrucción switch:

  • Primero se evalúa la expresión y salta al case cuyo valor coincida con el valor de la expresión.
  • Se ejecutan las instrucciones que contiene el case seleccionado hasta que se encuentra un break o hasta el final del switch. El break produce un salto y la ejecución continúa por la siguiente instrucción a continuación del switch.
  • Si el valor de la expresión no coincide con ningún case se ejecuta el bloque default.

El bloque default es opcional por lo tanto no es obligatorio que exista siempre un bloque default en un switch. El bloque default suele escribirse de forma habitual al final del switch a continuación de todos los case pero no es obligatorio escribirlo al final, puede aparecer en cualquier lugar.

Los valores que aparecen en los case deben ser únicos. No puede haber dos case con el mismo valor.

El valor de un case no puede ser una variable. Debe ser un literal o una constante (variables declaradas como final).

Ejemplo de switch: programa que lee por teclado un número de mes y muestra el nombre de mes correspondiente.
//Programa que pide un número de mes y muestra 
//el nombre de mes correspondiente
import java.util.*;
public class EjemploSwitch {
    public static void main(String[] args) {
        int mes;
        Scanner sc = new Scanner(System.in);
        System.out.print("Introduzca un numero de mes: ");                                                        
        mes = sc.nextInt();
        switch (mes) {  //inicio del switch
                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("Mes no válido");                        
        }  //fin del switch
    }
}

Ejemplo de switch: programa que lee por teclado un String correspondiente al nombre de un mes y muestra el número de días que tiene.

// Programa que pide un nombre de mes y muestra el número de días correspondiente                                 
import java.util.Scanner;
public class Ejemplo2Switch {
    public static void main(String[] args) {
        String mes;
        Scanner sc = new Scanner(System.in);
        System.out.print("Introduzca un nombre de mes: ");
        mes = sc.nextLine();
        switch (mes.toUpperCase()) {
            case "ENERO":
                System.out.println("31 DÍAS");
                break;
            case "FEBRERO":
                System.out.println("28 ó 29 DÍAS");
                break;
            case "MARZO":
                System.out.println("31 DÍAS");
                break;
            case "ABRIL":
                System.out.println("30 DÍAS");
                break;
            case "MAYO":
                System.out.println("31 DÍAS");                                                                    
                break;
            case "JUNIO":
                System.out.println("30 DÍAS");
                break;
            case "JULIO":
                System.out.println("31 DÍAS");
                break;
            case "AGOSTO":
                System.out.println("31 DÍAS");
                break;
            case "SEPTIEMBRE":
                System.out.println("30 DÍAS");
                break;
            case "OCTUBRE":
                System.out.println("31 DÍAS");
                break;
            case "NOVIEMBRE":
                System.out.println("30 DÍAS");
                break;
            case "DICIEMBRE":
                System.out.println("31 DÍAS");                                                                    
                break;
            default:
                System.out.println("Mes no válido");
        }
    }
}

Un case puede contener además de instrucciones que se ejecuten en secuencia, otras instrucciones como condiciones o bucles o incluso otro switch.

Ejemplo: programa que pide por teclado dos números enteros y un operador +, -, *, / y realiza y muestra el resultado de la operación según el operador introducido. Si se introduce el operador división, se comprueba si el divisor es cero, en ese caso la división no se puede realizar y se muestra un mensaje indicándolo.

//Programa que pide dos números y un operador y muestra el resultado de la operación                              
import java.util.*;
import java.io.*;
public class Ejemplo3Switch {
    public static void main(String[] args) throws IOException{
        int A,B, Resultado = 0 ;
        char operador;
        boolean calculado = true;
        Scanner sc = new Scanner(System.in);
        System.out.print("Introduzca un numero entero:");
        A = sc.nextInt();
        System.out.print("Introduzca otro numero entero:");
        B = sc.nextInt();
        System.out.print("Introduzca un operador (+,-,*,/):");                                                    
        operador = (char)System.in.read();
        switch (operador) {
                case '-' : Resultado = A - B;
                           break;
                case '+' : Resultado = A + B;
                           break;
                case '*' : Resultado = A * B;
                           break;
                case '/' : if(B!=0){
                              Resultado = A / B; 
                           }else{
                              System.out.println("\nNo se puede dividir por cero");                               
                              calculado = false;
                           }
                           break;
                default : System.out.println("\nOperador no valido");
                          calculado = false;               
        }
        if(calculado){
            System.out.println("\nEl resultado es: " + Resultado);                                                
        }
    }
}

Si una misma instrucción o bloque de instrucciones se tienen que ejecutar para distintos valores, en ese caso podemos escribir case multiples. Esto consiste en escribir varias instrucciones case seguidas.

Ejemplo de switch con case multiples: programa que pide introducir por teclado un número entero entre 1 y 7 correspondiente a un día de la semana y muestra un mensaje indicando si ese día hay clase de programación o no.

import java.util.*;
public class Ejemplo4Switch {
    public static void main(String[] args) {                                                                      
        int numeroDia;
        Scanner sc = new Scanner(System.in);
        System.out.print("Introduzca el numero del día de la semana (1 a 7): ");
        numeroDia = sc.nextInt();
        switch (numeroDia){
                case 1:  
                case 3: 
                case 5: System.out.println("Tenemos clase de programación");
                        break;
                case 2:
                case 4: System.out.println("Vaya, que pena");
                        System.out.println("Hoy no tenemos clase de programación");                               
                        break;
                case 6:
                case 7: System.out.println("Estoy deseando que llegue el lunes!!"); 
                        break;
                default : System.out.println("Número de día no válido");                                          
        }
    }
}

En este programa si se introduce por ejemplo un 1 como número de día, la ejecución pasará al case 1 y comienza a ejecutar las instrucciones que encuentre desde ahí hacia abajo hasta encontrar un break.

Es importante entender que una vez que la ejecución del programa entra en uno de los case, el programa sigue ejecutándose desde ese punto hasta que encuentre el primer break (estén dentro del mismo case o no) o hasta que se llegue al final del switch en cuyo caso continuará por la instrucción que se encuentre a continuación del switch.

Ejemplo: programa que pide un valor entero por teclado entre 1 y 6 y realiza una serie de operaciones con él dependiendo de su valor inicial.

import java.util.*;
public class Ejemplo5Switch {
    public static void main(String[] args) {
        int x, y = 10;
        Scanner sc = new Scanner(System.in);
        System.out.print("Introduzca un número >= 1 y <= 6: ");                                                   
        x = sc.nextInt();
        switch (x){
                case 1: x--;
                case 2: x+=5;
                case 3: x = x + y;
                        break;
                case 4:
                case 5: 
                case 6: x++;
                        break;
                default : System.out.println("Número no válido");                                                 
        }
        System.out.println("x = " + x);
    }
}

Si en este programa se introduce un 1 como valor para la x, en el switch se entrará en el case 1 y se ejecutarán todas las instrucciones hacia abajo hasta encontrar un break, es decir, si x es un 1 se ejecutan las instrucciones:

x--;

x+=5;

x = x + y;

Siete ejemplos de ejecución de este programa:

Introduzca un número >= 1 y <= 6: 1  
x = 15
Introduzca un número >= 1 y <= 6: 2  
x = 17
Introduzca un número >= 1 y <= 6: 3  
x = 13
Introduzca un número >= 1 y <= 6: 4  
x = 5
Introduzca un número >= 1 y <= 6: 5  
x = 6
Introduzca un número >= 1 y <= 6: 6  
x = 7
Introduzca un número >= 1 y <= 6: 0  
Número no válido
x = 0

2.3 OPERADOR CONDICIONAL ? :

El operador condicional se puede utilizar en sustitución de la instrucción condicional if-else.

Lo forman los caracteres  ?  y  :

Sintaxis:

expresión1 ? expresión2 : expresión3

Si expresión1 es cierta entonces se evalúa expresión2 y éste será el valor que devuelve el operador. Si expresión1 es falsa, se evalúa expresión3 y éste será el valor que devuelve el operador.

Ejemplo: programa que pide por teclado un número entero y muestra si es positivo o negativo. Consideramos el cero como positivo.

import java.util.Scanner;
public class OperadorCondicional {
    public static void main(String[] args) {                                                                      
        Scanner sc = new Scanner(System.in);
        int num;
        System.out.println("Introduzca numero: ");
        num = sc.nextInt();
        System.out.println(num >= 0 ? "POSITIVO" : "NEGATIVO");                                                   
    }
}

En el ejemplo, la instrucción:

System.out.println(num >= 0 ? "POSITIVO" : "NEGATIVO");  

Es equivalente a escribir esto:

if(num >= 0){
   System.out.println("POSITIVO");          
}else{
   System.out.println("NEGATIVO");
}

Ejemplo: programa que pide por teclado un número entero y muestra si es par o impar.

import java.util.*;
public class Ejemplo1OperadorCondicional2 {                                                                       
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num;       
        System.out.println("Introduzca numero: ");
        num = sc.nextInt();
        System.out.println(num%2 == 0 ? "PAR" : "IMPAR");                                                         
    }
}

En el ejemplo, la instrucción:

System.out.println(num%2 == 0 ? "PAR" : "IMPAR");  

Es equivalente a escribir esto:

if(num%2 == 0){
   System.out.println("PAR");
}else{
   System.out.println("IMPAR");     
}

Puedes encontrar más ejercicios para seguir practicando en este libro.


Contiene ejercicios resueltos sobre los conceptos básicos del lenguaje java: Declaración de variables, literales, tipos de datos, operadores, crear expresiones algebraicas correctas, etc.

Las soluciones de los ejercicios incluyen una explicación detallada sobre cómo se ha resuelto.

El contenido del libro es una recopilación de ejercicios realizados en mis clases de Programación en los ciclos formativos de grado superior Desarrollo de aplicaciones web y Desarrollo de aplicaciones multiplataforma.

3. ESTRUCTURA REPETITIVA O ITERATIVA

Esta estructura de control permite ejecutar de forma repetida una instrucción o un bloque de instrucciones.

Las instrucciones se repiten mientras que se cumpla una determinada condición.

Esta condición se conoce como condición de salida del bucle.

En Java las estructuras repetitivas se implementan mediante:

  • ciclo while
  • ciclo do .. while
  • ciclo for

3.1 CICLO WHILE

Las instrucciones se repiten mientras la condición sea cierta.

En un ciclo while la condición se comprueba al principio del bucle por lo que las instrucciones que lo forman se ejecutan 0 ó más veces.
 
Representación en diagrama de flujo de un bucle do .. while:
 
 
 
 Sintaxis:
 

instrucción 1;

while (condición){ //inicio while

        instrucciones;

}  //fin while

instrucción 2;
 
 
 
 

 La ejecución de un bucle while sigue los siguientes pasos:

  1. Se evalúa la condición.
  2. Si el resultado es false las instrucciones no se ejecutan y el programa sigue ejecutándose por la siguiente instrucción a continuación del while.
  3. Si el resultado es true se ejecutan las instrucciones y se vuelve al paso 1 
Ejemplo: programa que pide introducir números enteros por teclado. La lectura de números termina cuando se introduce un número negativo. El programa muestra la suma de todos los números introducidos excepto el negativo.   
/*
 * Programa que lee números hasta que se lee un negativo y muestra la
 * suma de los números leídos 
 */
import java.util.*;
public class Ejemplo1While {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num;       //variable que contiene el número introducido
        int suma = 0;  //variable donde acumularemos la suma de los números                                       

        System.out.print("Introduzca un número ( < 0 para finalizar): ");
        num = sc.nextInt(); //lectura del primer número

        while (num >= 0){ //inicio del bucle while                          
               suma = suma + num; //se suma el número introducido
               System.out.print("Introduzca un número ( < 0 para finalizar): ");                                  
               num = sc.nextInt(); //lectura del siguiente número
        } //fin del bucle while
        System.out.println("La suma es: " + suma ); //se muestra la suma
    }
}

En este ejemplo, según el enunciado, se trata de leer números enteros hasta que se introduzca un número negativo, por lo tanto, las instrucciones contenidas dentro del while se repiten mientras el número que introduzcamos sea >= 0.

Este es un ejemplo de estructura repetitiva en el que no sabemos a priori cuántas veces se repetirán las instrucciones. El número de iteraciones del bucle depende del valor de la variable num que se introduce por teclado. En el ejemplo podemos ver también que la lectura del primer número se realiza antes de que comience la estructura while. Hay que hacerlo así porque es posible que el primer número que se introduzca sea el negativo, en ese caso no tendríamos que sumarlo, por lo tanto el while no se debe ejecutar y se muestra directamente el mensaje con la suma del número.

Esta técnica se conoce como lectura adelantada o anticipada y es la forma correcta de utilizar la estructura while cuando no sabemos el número de iteraciones que se van a realizar.

Dos ejemplos de ejecución del programa:
Introduzca un número ( < 0 para finalizar): 6
Introduzca un número ( < 0 para finalizar): 2
Introduzca un número ( < 0 para finalizar): 5     
Introduzca un número ( < 0 para finalizar): -1
La suma es: 13
En este caso se introducen los números 6, 2 y 5. Cuando se introduce el valor -1 el bucle finaliza y se muestra la suma.
Introduzca un número ( < 0 para finalizar): -2
La suma es: 0
En este ejemplo de ejecución el primer número introducido es negativo por lo que el bucle while no se ejecuta. Se muestra el resultado de la suma que en este caso será 0.
 
Ejemplo: programa que muestra N asteriscos por pantalla. El valor de N se introduce por teclado. 
/* 
 * programa que lee un número n y muestra n asteriscos
 */
import java.util.*;

public class Ejemplo2While {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N; //variable que contiene el número de asteriscos a mostrar
        int contador = 0; //variable para contar los asteriscos que se han mostrado                               
        System.out.print("Introduce número de asteriscos a mostrar: ");
        N = sc.nextInt(); //leemos el número total de asteriscos a mostrar

        while (contador < N){ //inicio del bucle while                                                            
               System.out.print("*");
               contador++;
        }  //fin del bucle while
        System.out.println("Fin programa");
    }
}

En este programa se trata de mostrar tantos asteriscos como indique el número N que se ha introducido por teclado.

Este es un ejemplo de estructura repetitiva en la que sabemos a priori cuántas veces se va a repetir el while. En este caso el while se va a repetir N veces. La variable contador será la variable de control que hará que el while termine. Cada vez que se muestra un asterisco por pantalla se suma 1 a esta variable. El while se repite mientras el valor del contador sea menor que el número total de asteriscos a mostrar.

Dos ejemplos de ejecución:
Introduce número de asteriscos a mostrar: 10   
**********
Fin programa
Introduce número de asteriscos a mostrar: 0    

Fin programa

Ejemplo: programa que muestra una tabla con temperaturas expresadas en grados Fahrenheit y su equivalente en grados Celsius. Los valores de las temperatura en grados Fahrenheit estarán comprendidas entre 10 ºF y 100 ºF y se mostrarán con un incremento de 10º entre ellas (10, 20, 30 ...).

Fórmula para pasar de ºF a ºC:     ºC = (ºF – 32) * 5 / 9 
public class Ejemplo3While {
    public static void main(String[] args) {
        int fahrenheit = 10; //contiene las temperaturas fahrenheit                                               
        double celsius;      //contiene las temperaturas celsius
        System.out.printf(" ºF \t  ºC \n");
        System.out.println("---------------");
        while (fahrenheit <= 100 ){ //inicio del bucle while
               celsius = (fahrenheit - 32)*5/9.0;
               System.out.printf("%3d\t%6.2f \n", fahrenheit, celsius);                                           
               fahrenheit += 10;
        }  //fin del bucle while
    }
}
Salida por pantalla:
 ºF 	 ºC 
---------------
 10	  -12,22               
 20	   -6,67 
 30	   -1,11 
 40	    4,44 
 50	   10,00               
 60	   15,56 
 70	   21,11 
 80	   26,67 
 90	   32,22 
100	   37,78

En este ejemplo la variable fahrenheit es la variable de control y será la encargada de determinar cuando finaliza el bucle while.

Su valor inicial es 10 y se deben mostrar las temperaturas desde 10ºF hasta 100ºF de 10 en 10, por lo tanto en cada iteración se incrementará su valor en 10.

El while se repite mientras el valor de la variable sea <= 100.
 
3.2 CICLO DO - WHILE
 
Las instrucciones se ejecutan mientras la condición sea cierta.

La condición se comprueba al final del bucle por lo que el bloque de instrucciones se ejecutarán al menos una vez.

Esta es la diferencia fundamental entre el bucle while y el bucle do .. while. Las instrucciones de un bucle while es posible que no se ejecuten si la condición inicialmente es falsa.

Diferencia entre un bucle while y un bucle do .. while:
  • Bucle while se ejecuta 0 o más veces.
  • Bucle do .. while se ejecuta 1 o más veces. 
Representación en diagrama de flujo de un bucle do .. while:



 
 Sintaxis do .. while:

instrucción1;
do{  //inicio do .. while
    instrucciones;
}while(condición);  //fin do .. while
instrucción2;
 
 
 
 
 
 
 
La ejecución de un bucle do - while sigue los siguientes pasos:
  1. Se ejecutan las instrucciones a partir de la instrucción do{
  2. Se evalúa la condición.
  3. Si la condición no se cumple el programa sigue ejecutándose por la siguiente instrucción a continuación del  while.
  4. Si la condición se cumple volvemos al paso 1.
Ejemplo: Programa que lee un número entero menor o igual que 100. Si el número es mayor que 100 se muestra un mensaje indicándolo y se vuelve a pedir. Finalmente se muestra por pantalla el número introducido.
//Programa que pide un número menor o igual que 100
import java.util.Scanner;
public class Ejemplo1DoWhile {
    public static void main(String[] args) {
        int valor;
        Scanner in = new Scanner( System.in );
        do {  //inicio del do .. while
            System.out.print("Introduce un número entero <= 100: ");                                              
            valor = in.nextInt();
            if(valor > 100){
                System.out.println("Número no válido");
            }
        }while (valor > 100);  //fin del do .. while
        System.out.println("Ha introducido: " + valor);                                                           
    }
}
Dos ejemplos de ejecución:
Introduce un número entero <= 100: 27   
Ha introducido: 27
Introduce un número entero <= 100: 690  
Número no válido
Introduce un número entero <= 100: 584  
Número no válido
Introduce un número entero <= 100: 58
Ha introducido: 58

En los ejemplos podemos comprobar que las instrucciones dentro del bucle do .. while se ejecutan al menos una vez.

Ejemplo: Programa que lee un número entero entre 1 y 10 ambos valores incluidos. Si el número es válido se muestra un mensaje indicándolo y se vuelve a pedir. Finalmente se muestra por pantalla el número introducido. 
// Programa que lee un número entre 1 y 10 
import java.util.Scanner;
public class Ejemplo2DoWhile {
    public static void main(String[] args) {
        int n;
        Scanner sc = new Scanner(System.in);
        do {  //inicio del do .. while
            System.out.print("Escribe un número entero entre 1 y 10: ");                                          
            n = sc.nextInt();
            if (n < 1 || n > 10) {
                System.out.println("Valor no válido");
            }
        } while (n < 1 || n > 10);   //fin del do .. while                                                        

        System.out.println("Ha introducido: " + n);
    }
}
Dos ejemplos de ejecución del programa:
Escribe un número entero entre 1 y 10: 3  
Ha introducido: 3
Escribe un número entero entre 1 y 10: -2  
Valor no válido
Escribe un número entero entre 1 y 10: 6
Ha introducido: 6
Ejemplo: Programa que muestra los números del 1 al 10 todos en la misma fila y separados por un espacio en blanco.
import java.util.Scanner;
public class Ejemplo3DoWhile {
    public static void main(String[] args) {                                                                      
        int i = 1;
        do {   //inicio del do .. while
            System.out.print(i + " ");
            i++;
        } while (i<=10);   //fin del do .. while                                                                  
        System.out.println("\nFin programa");
    }
}
El programa muestra por pantalla:
1 2 3 4 5 6 7 8 9 10   
Fin programa
En este caso la variable i es la que contienen los valores a mostrar por pantalla. También es la variable de control que determina cuando finaliza el bucle. Inicialmente vale 1 y en cada iteración, después de mostrar su valor por pantalla se incrementa. El do .. while se repite mientras el valor de i sea menor o igual a 10.
 
3.3 CICLO FOR

Un for hace que una instrucción o bloque de instrucciones se repitan un número determinado de veces mientras se cumpla la condición.

Los bucles for son los más adecuados cuando se conoce el número de veces que se van a repetir las instrucciones.

Representación en diagrama de flujo de una instrucción for:


Sintaxis Java del bucle for:

instrucción1;

for(inicialización; condición; incremento/decremento){ //inicio for

     instrucciones;

}  //fin for

instrucción2;

A continuación de la palabra for y entre paréntesis debe haber siempre tres zonas separadas por punto y coma:

  • zona de inicialización.
  • zona de condición
  • zona de incremento ó decremento. 

 

Las tres zonas son opcionales. Si en alguna ocasión no fuese necesario escribir alguna de estas zonas se pueden dejar en blanco, pero los punto y coma deben aparecer.

Inicialización es la parte en la que la variable o variables de control del bucle toman su valor inicial. Puede haber una o más instrucciones en la zona de inicialización. Si hay varias instrucciones deben estar separadas por comas. La inicialización se realiza solo una vez.

Condición es una expresión booleana que determina si la sentencia o bloque de sentencias se ejecutan o no. Las instrucciones contenidas dentro del bucle for se ejecutan mientras que la condición sea cierta.

Incremento/decremento es una expresión que modifica la variable o variables de control del bucle. En esta zona puede haber más de una expresión para modificar las variables. Si hay varias expresiones deben estar separadas por comas.

La ejecución de un bucle for sigue los siguientes pasos:

  1. Se inicializa la variable o variables de control (zona de inicialización)
  2. Se evalúa la condición (zona de condición).
  3. Si la condición es falsa, finaliza la ejecución del for  y el programa continúa su ejecución en la siguiente instrucción después del for.
  4. Si la condición es cierta se ejecutan las instrucciones contenidas dentro del for.
  5. Se actualiza la variable o variables de control (zona incremento/decremento)
  6. Se vuelve al punto 2.

Igual que el bucle while, un bucle for se puede ejecutar 0 ó más veces.

Ejemplo: Programa que muestra los números del 1 al 10 ambos incluidos todos en la misma línea y separados por un espacio en blanco.  
/*
 * programa que muestra los números del 1 al 10                                                                   
 */
public class Ejemplo1For {
    public static void main(String[] args) {
        int i;
        for (i = 1; i <= 10; i++) {    //inicio del for
            System.out.print(i + " ");
        }  //fin del for
        System.out.println("\nFin programa");                                                                     
    }
}
Salida por pantalla:
1 2 3 4 5 6 7 8 9 10   
Fin programa
La instrucción for del ejemplo la podemos interpretar de esta forma:

Primero asigna a i el valor inicial 1 y a continuación se comprueba la condición. Mientras que i sea menor o igual a 10 muestra i + " ", a continuación incrementa el valor de i y se comprueba de nuevo la condición. El for se repite mientras i sea <= 10.

En los programas de este tipo en los que la variable de control, en este caso la i, solo se utiliza dentro del bucle for es habitual declararla en la zona de incialización. Si lo hacemos de esa forma el programa quedaría así:

// Programa que muestra los números del 1 al 10
public class Ejemplo1For {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {    //inicio del for                                                       
            System.out.print(i + " ");
        }  //fin del for
        System.out.println("\nFin programa");                                                                     
    }
}
Ejemplo: Programa que muestra los números del 10 al 1 ambos incluidos todos en la misma línea y separados por un espacio en blanco.
// Programa que muestra los números del 10 al 1
public class Ejemplo2For {
    public static void main(String[] args) {
        for (int i = 10; i > 0; i--) {    //inicio del for                                                        
            System.out.print(i + " ");
        }  //fin del for
        System.out.println("\nFin programa");                                                                     
    }
}
Salida por pantalla:
10 9 8 7 6 5 4 3 2 1   
Fin programa
La instrucción for del ejemplo la podemos interpretar así:

Primero asigna a i el valor inicial 10 y a continuación se comprueba la condición. Mientras que i sea mayor que 0 muestra i + " ", a continuación se decrementa el valor de i y se comprueba de nuevo la condición. El for se repite mientras i sea > 0.

Ejemplo: Vamos a hacer de nuevo el programa que muestra una tabla con temperaturas expresadas en grados Fahrenheit y su equivalente en grados Celsius pero esta vez utilizaremos un bucle for para resolverlo. El programa debe realizar los mismo que el anterior, los valores de las temperatura en grados Fahrenheit estarán comprendidas entre 10 ºF y 100 ºF y se mostrarán con un incremento de 10º entre ellas (10, 20, 30 ...).

//Programa que muestra una tabla de equivalencias entre grados Fahrenheit y celsius
public class Ejemplo3For {
    public static void main(String[] args) {                                                                      
        double celsius;
        System.out.printf(" ºF \t  ºC \n");
        System.out.println("---------------");
        for (int fahrenheit = 10; fahrenheit <= 100; fahrenheit+= 10) {                                           
             celsius = (fahrenheit - 32)*5/9.0;
             System.out.printf("%3d\t%6.2f \n", fahrenheit, celsius);
        }
    }
}
Salida por pantalla:
 ºF      ºC 
---------------
 10	  -12,22       
 20	   -6,67 
 30	   -1,11 
 40	    4,44 
 50	   10,00 
 60	   15,56 
 70	   21,11 
 80	   26,67 
 90	   32,22 
100	   37,78
La instrucción for del ejemplo la podemos interpretar así:

Primero asigna a fahrenheit el valor inicial 10 y a continuación se comprueba la condición. Mientras que  fahrenheit sea menor o igual que 100 se ejecutan las instrucciones del for, a continuación se incrementa el valor de  fahrenheit en 10 y se comprueba de nuevo la condición. El for se repite mientras fahrenheit sea <= 100.

Ejemplo: Dadas dos variables enteras a y b con valor inicial 1, escribimos un programa que muestre una tabla con el valor de ambas variables y su suma. En cada iteración el valor de a se incrementa en 1 unidad y el valor de b se incrementa en 2 unidades. La tabla finaliza cuando la suma de a y b sea >= 10.

Este es un ejemplo de programa que utiliza varias variables en las zonas de inicialización e incremento/decremento. 
// Programa que muestra el valor de a, b y su suma mientras que la suma sea menor de 10. 
// En cada iteración el valor de a se incrementa en 1 unidad y el de b en 2
public class Ejemplo4For {
    public static void main(String[] args) {                                                                      
        for(int a = 1, b = 1; a + b < 10; a++, b+=2){
            System.out.println("a = " + a + "  b = " + b + "  a + b = " + (a+b));                                 
        }
    }
}
La salida de este programa es: 
a = 1  b = 1  a + b = 2   
a = 2  b = 3  a + b = 5
a = 3  b = 5  a + b = 8
La instrucción for del ejemplo la podemos interpretar así: Primero asigna a las variables a y b el valor 1 y a continuación se comprueba la condición. Mientras que la suma de a + b sea menor que 10 se ejecuta las instrucción del for, a continuación se suma 1 a la variable a y se suma 2 a la variable b y se comprueba de nuevo la condición. El for se repite mientras que la suma a +b sea menor que 10.
 
Un error que se puede cometer cuando escribimos un for es escribir el punto y coma después del paréntesis final. Un bucle for generalmente nunca lleva punto y coma final. 

Por ejemplo el bucle:

for (int i = 1; i <= 10; i++);

{

     System.out.println("Elementos de Programación");

}

no visualiza la frase "Elementos de Programación" 10 veces como cabría esperar, ni produce un mensaje de error por parte del compilador.

En realidad lo que sucede es que se visualiza una vez la frase "Elementos de Programación", ya que aquí la sentencia for es una sentencia vacía, sin instrucciones a realizar, al terminar con un punto y coma (;).

El for en este caso se limita a realizar la asignación inicial de la variable, y mientras se cumpla la condición incrementar el valor de i. La variable i toma como valor incial 1 y cuando el for termina valdrá 11. A continuación se mostrará el mensaje por pantalla.
 
¿Que estructura repetitiva usar?

Aunque un for se puede utilizar también cuando no se sabe a priori el número de iteraciones a realizar, esta instrucción es especialmente indicada para bucles donde se conozca el número de pasadas.

Como regla práctica podemos decir que:
  • La instrucción for se utiliza generalmente cuando se conoce el número de iteraciones a realizar.
  • Las instrucciones while y do-while se utilizan generalmente cuando no se conoce a priori el número de iteraciones a realizar.
  • La instrucción do .. while será más adecuada que la instrucción while cuando el bloque de instrucciones se deban repetir al menos una vez.
3.4 BUCLES ANIDADOS

Hablamos de bucles anidados cuando se incluyen instrucciones for, while o do-while unas dentro de otras. Los anidamientos de estas estructuras tienen que ser correctos, es decir, una estructura anidada dentro de otra lo debe estar totalmente, sin solaparse una con la otra.

Sintaxis para anidar dos bucles for:

for(inicialización; condición; incremento/decremento){ //inicio del for1                                          
     instrucciones1;
     for(inicialización; condición; incremento/decremento){ //inicio for2
         instrucciones2;   //instrucciones que se ejecutan en for2                                                
     }  //fin del for2
     instrucciones3;
}  //fin del for1
Sintaxis para anidar dos bucles while:
while(condición){   //inicio del while 1
      instrucciones1;
      while(condición){   //inicio del while 2                                                                    
            instrucciones2;
      }   //fin del while 2                                                                                       
      instrucciones3;
}
Sintaxis para anidar dos bucles do .. while:
do{  //inicio del do .. while 1
   instrucciones1;
   do{   //inicio del do .. while 2                                                                               
      instrucciones2;
   }while(condición);  //fin del do .. while 2                                                                    
   instrucciones3;     
}while(condición);   // fin del do .. while 1
Los bucles se pueden anidar aunque sean de tipos distintos, por ejemplo podríamos anidar un bucle for dentro de un do .. while y éste a su vez dentro de un while de esta forma: 
while(condición){   //inicio del while
      instrucciones1;
      do{  //inicio del do .. while
         instrucciones2;
         for(inicialización; condición; incremento/decremento){ //inicio del for                                  
             instrucciones3;
         }  //fin del for
         instrucciones4;
      }while(condición);  //fin del do .. while                                                                   
      instrucciones5;
}  //fin del while
Ejemplo: programa que dibuja un rectángulo formado por asteriscos. El número de filas y columnas del rectángulo se pide por teclado. El número de filas y de columnas debe ser > 1.
// Rectángulo sólido de asteriscos.
import java.util.Scanner;
public class Ejemplo1BuclesAnidados {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int filas, columnas;
        //leer número de filas hasta que sea un número > 1                                                        
        do{
           System.out.print("Introduce número de filas: ");
           filas = sc.nextInt();
        }while(filas < 2);
        //leer número de columnas hasta que sea un número > 1
        do{
           System.out.print("Introduce número de columnas: ");
           columnas = sc.nextInt();
        }while(columnas < 2);
        for(int i = 1; i <= filas; i++){    //for para las filas
            for(int j = 1; j <= columnas; j++){   //for para las columnas                                           
                System.out.print(" * ");
            }  //fin del for para las columnas
            System.out.println();
        }  //fin del for para las filas 
    }
}
Ejemplo de ejecución:
Introduce número de filas: 6
Introduce número de columnas: 10     
 *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  *  *        
 *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  *  *

En este programa se han anidado dos bucles for para mostrar el rectángulo de asteriscos.

El bucle for externo es el que corresponde a las filas. El for interno corresponde a las columnas.

Para cada una de las filas se ejecuta completamente el for de las columnas con lo que se consigue que para cada fila se muestren tantos asteriscos como columnas haya.

Al final de cada fila se escribe un salto de línea para que la siguiente fila comience a mostrarse en la línea siguiente.

Ejemplo: programa que dibuja un cuadrado formado por dígitos del 0 al 9. El número de filas del cuadrado se pide por teclado. El número de filas debe ser > 1.

import java.util.Scanner;
public class Ejemplo2BuclesAnidados {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int filas, columnas, contador = 0;
        //leer número de filas del cuadrado
        do{
           System.out.print("Introduce número de filas del cuadrado: ");                                          
           filas = sc.nextInt();
        }while(filas<2);
        for(int i = 1; i<=filas; i++){    //filas
            for(int j = 1; j<=filas; j++){   //columnas = filas                                                   
                 System.out.print(contador % 10 + " ");
                 contador++;
            } //fin del for para las columnas
            System.out.println();
        } //fin del for para las filas  
    }
}

Ejemplo de ejecución:  

Introduce número de filas del cuadrado: 6   
0 1 2 3 4 5 
6 7 8 9 0 1 
2 3 4 5 6 7 
8 9 0 1 2 3 
4 5 6 7 8 9 
0 1 2 3 4 5

Ejemplo: A partir de una variable x que tomará los valores desde 1 hasta 10, mostrar una tabla de potencias de x. Para cada valor de x se mostrará   x2    x3     x4

/* 
 * Programa que muestra una tabla con las potencias de x (x x2 x3 x4)
 * para valores de x desde 1 hasta 10
 */
import java.util.Scanner;
public class Ejemplo1BuclesAnidados3{
    public static void main(String[] args) {
        int x, n;
        //mostrar la cabecera de la tabla
        System.out.printf("%10s%10s%10s%10s%n", "x", "x^2", "x^3", "x^4");                                        
        for (x = 1; x <= 10; x++) {   //filas
            for (n = 1; n <= 4; n++) {   //columnas
                System.out.printf("%10.0f", Math.pow(x, n));                                                      
            }  //fin del for para las columnas
            System.out.println();
        } //fin del for para las filas
    }
}

La salida de este programa es:

         x       x^2       x^3       x^4   
         1         1         1         1
         2         4         8        16
         3         9        27        81
         4        16        64       256
         5        25       125       625
         6        36       216      1296
         7        49       343      2401
         8        64       512      4096
         9        81       729      6561
        10       100      1000     10000 

4. INSTRUCCIONES DE SALTO

Una instrucción de salto provoca la modificación del flujo de ejecución de un programa.

Java ofrece dos instrucciones de salto:

  • break
  • continue

4.1 BREAK

Esta instrucción provoca la finalización de una instrucción switch, while, do-while o for. En aquellos casos en los que existan estructuras de control repetitivas anidadas, un break produce la salida inmediata de aquel bucle en el que se encuentre incluida pero no de los demás.

La única situación en la que un buen programador debería utilizar la instrucción break, es para separar los diferentes casos de una instrucción switch.

Ejemplo: Programa que muestra números desde 1 hasta 50. Cuando encuentre el primer número que sea múltiplo de 3 y de 5 dejará de mostrar números.

public class Ejemplo1Break {
    public static void main(String[] args) {
           for (int i = 1; i <= 50; i++) {  //inicio del for                                                       
                if (i % 3 == 0 && i % 5 == 0) {
                    break;     //provoca el final del for
                }
                System.out.println(i);
           } //fin del for
           System.out.println("Hasta Pronto!!!");                                                                 
    }
}

En este ejemplo, cuando se ejecuta la instrucción break el for finaliza y la ejecución del programa continúa en la instrucción que aparece a continuación del for.

4.2 CONTINUE

Esta instrucción provoca la ejecución de la siguiente iteración en el bucle, es decir, se salta las instrucciones que quedan hasta el final del bucle, y vuelve al inicio del mismo. Si se trata de un bucle for vuelve a la zona de incremento/decremento.

Un buen programador deberá evitar el uso de esta instrucción.

Ejemplo: Programa que muestra los números desde el 1 hasta el 50 excepto los que sean múltiplos de 3 y de 5.

public class Ejemplo1Continue {
    public static void main(String[] args) {
        for (int i = 1; i <= 50; i++) {   //inicio del for                                                        
            if (i % 3 == 0 && i % 5 == 0) {
                continue; //siguiente iteracicón del for                                                          
            }
            System.out.println(i);
        }  //fin del for
    }
}