Operaciones y Sentencias
4. Operadores y sentencias
4.1. Entender los operadores de Java
Los operadores de java son símbolos especiales que se aplican un grupo de variables, valores o “literales” y que devuelven un valor. Existen tres tipos de operadores en Java: unario, binario y ternario. Estos tipos de operadores pueden ser aplicados a uno, dos o tres operandos. Los operadores de java no siempre se evalúan de izquierda a derecha. En el siguiente ejemplo se puede observar como la expresión se evalúa de derecha a izquierda:
int y = 4; double x =
3 + 2 * --y;
| Operador | Símbolos y ejemplos |
|---|---|
| Operadores post-unarios | Expresión++, Expresión-- |
| Operadores pre-unarios | ++Expresión, --Expresión |
| Operadores unarios | +, -,! |
| Multiplicación, División, Módulo | *, /, % |
| Suma, Resta | +, - |
| Operadores de cambio | <<, >>, >>> |
| Operadores relacionales | <, >, <=, >=, instanceof |
| Igual, Distinto | ==, != |
| Operadores lógicos | &, ^, |
| Operadores lógicos de cortocircuito | &&, |
| Operadores ternarios | Expresión booleana? expresión1 : expresión 2 |
| Operadores de asignación | =, +=, -=, *=, /=, %=, &=, ^=, !=, <<=, >>=, >>>= |
4.2. Trabajando con operadores binarios aritméticos
4.2.1. Operadores aritméticos
Los operadores aritméticos son los utilizados en las matemáticas y son los siguiente: la suma (+), la resta (-), la multiplicación (*), la división (/) y el módulo (%). También se incluyen los operadores unarios
++ y --. Como puedes comprobar en la tabla anterior los operadores , / y % tienen mayor orden de
preferencia que los operadores + y -, por lo que la siguiente expresión:
int x = 2 * 5 + 3 * 4 – 8;
int x = 10 + 12 – 8;
int x = 2 * ((5 + 3) * 4 – 8);
int x = 2 * (8 * 4 - 8);
int x = 2 * (32 - 8);
int x = 2 * 24;
System.out.print(9 / 3); // Outputs 3
System.out.print(9 % 3); // Outputs 0
System.out.print(10 / 3); // Outputs 3
System.out.print(10 % 3); // Outputs 1
System.out.print(11 / 3); // Outputs 3
System.out.print(11 % 3); // Outputs 2
System.out.print(12 / 3); // Outputs 4
System.out.print(12 % 3); // Outputs 0
operación de módulo da como resultado un valor entre 0 y (y - 1) para dividendos positivos. Esto significa que el resultado de una operación de módulo es siempre 0,1 o 2. El funcionamiento del módulo no se limita a los valores enteros positivos en Java y también puede aplicarse a números enteros negativos y números enteros de coma flotante. Para un divisor “y” y dividendo negativo dado, el valor del módulo resultante está entre (-y + 1) y 0.
4.2.2. Promoción numérica
Reglas de la promoción numérica:
- Si dos variables tienes diferente tipo, Java automáticamente convertirá una de las variables al tipo más grande de las dos.
- Si una de las variables es Integer y la otra de coma flotante(float), Java automáticamente convertirá la variable Integer en una de coma flotante.
- Los tipos de datos pequeños como byte, short y char son convertidos a Int siempre que son usados por un operador aritmético binario, incluso si ninguno de los operandos es un Int.
- Después de que se hayan convertido las variables y los operandos tengan el mismo tipo, el resultado se guardará con el mismo tipo al que se hayan convertido los operandos. Las dos últimas reglas son aquellas con las que la mayoría de la gente tiene problemas. Por lo que respecta a la tercera regla, debe tenerse en cuenta que los operadores unitarios están excluidos de esta. Por ejemplo, aplicar ++ a un valor short dará como resultado un valor short.
4.3. Trabajando con operadores unarios
Por definición un operador unario es uno que requiere exactamente un operando o variable para funcionar. Como se muestra en la tabla suelen realizar tareas simples como incrementar en uno una variable o negar el valor de un boolean.
| Operador unario | Descripción |
|---|---|
| + | Indica que un número es positivo, aunque se supone que los números son positivos en Java a menos que vayan acompañados de un operador negativo unario. |
| - | Indica que un número es negativo o niega una expresión |
| ++ | Incremento una variable en 1 |
| -- | Decremento de una variable en 1 |
| ! | Invierte el valor lógico de un boolean |
4.3.1. Complemento lógico y operadores de negación
El operador de complemento lógico(!) invierte el valor de una expresión booleana. Por ejemplo, si el valor es true, se invertiría a false, y viceversa. Para demostrar esto, se comparará la salida de las siguientes instrucciones:
boolean x = false;
System.out.printl(x); //false x = !x;
System.out.println(x); //true
double x =
1.21;
System.out.println(x); //1.21 x = -x;
System.out.println(x); //-1.21 x = -x;
System.out.println(x); //1.21
int x = !5; // DOES NOT COMPILE boolean
y = -true; // DOES NOT COMPILE boolean
z = !0; // DOES NOT COMPILE
4.3.2. Operadores de incremento y decremento.
Los operadores de incremento y decremento (++, --) pueden aplicarse a operandos numéricos y tienen mayor preferencia que los operadores binarios. Los operadores de incremento y decremento requieren un cuidado especial ya que el orden en el que son utilizados con los operandos pueden provocar un procesamiento distinto de la expresión. Si el operador está situado delante del operando entonces el operador se aplica primero y luego se devuelve el valor. Por otro lado, si el operador se encuentra detrás del operando se devuelve primero el valor original y luego se aplica el operador. El siguiente código ilustra las diferencias:
int counter = 0;
System.out.println(counter); // Outputs 0
System.out.println(++counter); // Outputs 1
System.out.println(counter); // Outputs 1
System.out.println(counter--); // Outputs 1
System.out.println(counter); // Outputs 0
int x = 3;
int y = ++x * 5 / x-- + --x;
System.out.println("x is " + x);
System.out.println("y is " + y);
int y = 4 * 5 / x-- + --x; // x con valor 4
int y = 4 * 5 / 4 + --x; // x con valor 3
int y = 4 * 5 / 4 + 2; // x con valor 2
x is 2 y
is 7
4.4. Usando los operadores binarios adicionales
4.4.1. Operadores de asignación
Los operadores de asignación son operadores binarios que modifican la variable con el valor del lado derecho de la ecuación. El operador de asignación más simple es el operador “=”:
int x = 1;
int x = 1.0; // DOES NOT COMPILE
short y = 1921222; // DOES NOT
COMPILE int z = 9f; // DOES NOT COMPILE
long t = 192301398193810323; // DOES NOT COMPILE
4.4.2. Casting de valores primitivos
Se pueden arreglar los ejemplos de la sección anterior, haciendo “casting” a los resultados. El “casting” es necesario siempre que se pase de un dato numérico más grande a un tipo de datos numéricos más pequeños, o la conversión de un número float a un valor int.
int x = (int)1.0;
short y = (short)1921222; // Stored as 20678 int
z = (int)9l;
long t = 192301398193810323L;
short x = 10;
short y = 3;
short z = x * y; // DOES NOT COMPILE
short x = 10; short y = 3;
short z = (short)(x * y);
Overflow y Underflow
Las expresiones en el ejemplo anterior ahora compilan, aunque hay un coste. El segundo valor, 1.921.222, es demasiado grande para ser almacenado como un valor short, por lo que se produce un overflow y se convierte en 20.678. El overflow es cuando un número es tan grande que ya no se puede guardar dentro de un tipo de datos, por lo que el sistema se "envuelve" en el siguiente valor mínimo y
cuenta desde ahí. También hay un underflow analogo, cuando el número es demasiado bajo para guardarlo en el tipo de datos. Por ejemplo, la siguiente sentencia genera un número negativo:
_System.out.println(2147483647+1); // - 214748364848_
4.4.3. Operadores de asignación compuestos
Además del operador simple de asignación, =, existen también numerosos operadores de asignación compuestos. Sólo se requieren dos de los operadores compuestos enumerados en la Tabla 2.1, += y =. Los operadores complejos son en realidad una mejora de los operadores de asignación simple con una operación aritmética o lógica incorporada que se aplican de izquierda a derecha de la expresión y almacena el valor resultante en la variable de la parte izquierda de la pantalla. Por ejemplo, las dos expresiones siguientes después de la declaración de x y z son equivalentes:
int x = 2, z = 3; x = x * z; // Simple
assignment operator x *= z; // Compound
assignment operator
long x = 10; int y = 5;
y = y * x; // DOES NOT COMPILE
long x = 10;
int y = 5;
y*= x;
long x = 5; long
y = (x=3);
System.out.println(x); // Outputs 3
System.out.println(y); // Also, outputs 3
- En primer lugar, fija el valor de la variable x para que sea 3.
- En segundo lugar, devuelve el valor de la asignación, que también es 3.
4.4.4. Operadores relacionales
Ahora se pasará a los operadores relacionales, que comparan dos expresiones y devuelven un valor booleano. Los primeros cuatro operadores relacionales (ver la tabla se aplican solo a tipos de datos primitivos numéricos. Si los dos operando numéricos no son del mismo tipo de datos, el parámetro más pequeño se transforma de la manera anteriormente discutida.
| Operador relacional | Descripción |
|---|---|
| < | Estrictamente menos que |
| <= | Menos que o igual a |
| > | Estrictamente mayor que |
| >= | Mayor que o igual a |
A continuación, se verán unos ejemplos de estos operadores:
int x = 10, y = 20, z = 10;
System.out.println(x < y); // Outputs true
System.out.println(x <= y); // Outputs true
System.out.println(x >= z); // Outputs true
System.out.println(x > z); // Outputs false
| Operador relacional | Descripción |
|---|---|
| a instanceof b | Verdadero si la referencia a la que apunta “a” es una instancia de una clase, subclase o clase que implementa una interfaz particular, como se nombra en b |
Cabe destacar lo siguiente respecto al operador instanceof:
String str = null;
System.out.println(str instanceof String ); // false
if (x != null && x instanceof X) ...
if (x instanceof X) ...
4.4.5. Operadores lógicos
Los operadores lógicos, (&), (|) y (^), se pueden aplicar a datos de tipo numéricos y booleanos. Cuando se aplican a tipos de datos booleanos, se los denomina operadores lógicos. Alternativamente, cuando se aplican a tipos de datos numéricos, se les llama operadores a nivel de bit, ya que realizan comparacionesbit a bit de los bits que componen el número. Se debe familiarizar con las tablas de las figuras, donde se supone que x e y son tipos de datos booleanos.
| X & Y (AND) | ||
|---|---|---|
| Y=true | Y=false | |
| X = true | True | False |
| X = false | False | False |
| X | Y (Inclusive OR) | ||
|---|---|---|
| Y=true | Y=false | |
| X = true | True | True |
| X = false | True | False |
| X ^ Y (Exclusive OR) | ||
|---|---|---|
| Y=true | Y=false | |
| X = true | False | True |
| X = false | True | False |
Aquí hay algunos consejos para ayudar a recordar esta tabla:
- AND solo es verdadero si ambos operandos son verdaderos.
- OR inclusivo solo es falso si ambos operandos son falsos.
- Exclusive OR solo es verdadero si los operandos son diferentes.
Finalmente, se presentan los operadores condicionales, && y ||, que a menudo se conocen como
operadores de cortocircuito. Los operadores de cortocircuito son casi idénticos a los operadores lógicos, & y |, respectivamente, excepto que el lado derecho de la expresión nunca puede ser evaluado si el resultado final puede ser determinado por el lado izquierdo de la expresión. Por ejemplo, si se considera la siguiente declaración:
En referencia a las tablas de verdad, el valor x solo puede ser falso si ambos lados de la expresión son falsas. Como sabemos que el lado izquierdo es verdadero, no hay necesidad de evaluar el lado derecho, ya que nada hará que el valor de x sea diferente de verdadero. Para ilustrar este concepto prueba a ejecutar la línea de código anterior para varios valores de y. El ejemplo más común de dónde se usan los operadores de cortocircuito es la comprobación de objetos nulos antes de realizar una operación, como esta:
boolean x = true || (y < 4);En este ejemplo, si x fuera nulo, entonces el cortocircuito evita lanzar una excepción NullPointerException, ya que la evaluación de x.getValue () <5 nunca se alcanza. Alternativamente, si usamos un & lógico, entonces ambos lados siempre se evaluarán y cuando x fuese nulo esto arrojaría una excepción:if(x != null && x.getValue() < 5) { // Do something }¿Cuál es el resultado del siguiente código?if(x != null & x.getValue() < 5) { // Throws an exception if x is null // Do something }Como x >= 6 es verdadero, el operador de incremento en el lado derecho de la expresión nunca se evalúa, por lo que la salida es 6.int x = 6; boolean y = (x >= 6) || (++x <= 7); System.out.println(x);
4.4.6. Operadores de igualdad
La determinación de la igualdad en Java puede no ser trivial, ya que hay una diferencia semántica entre "dos objetos son lo mismo" y "dos objetos son equivalentes". Es aún más complicado por el hecho de que para tipos primitivos numéricos (entre los que se incluye también el tipo de dato char) y booleanos, no existe tal distinción. Comenzando por lo más sencillo: el operador de igualdad (==) y el operador de desigualdad (!=). Como los operadores relacionales, comparan dos operandos y devuelven un valor booleano si las expresiones o valores son iguales o no iguales, respectivamente. Los operadores de igualdad se utilizan en uno de tres casos:
- Comparando dos tipos primitivos numéricos. Si los valores numéricos son de diferente tipo de
datos, los valores se transforman automáticamente como se describió anteriormente.
Por ejemplo, 5 == 5.00 devuelve verdadero ya que el lado izquierdo se transforma a un double. - Comparando dos valores booleanos.
- Comparando dos objetos, incluidos los valores nulos y String.
Las comparaciones para la igualdad se limitan a estos tres casos, por lo que no se pueden mezclar tipos.
Por ejemplo, cada uno de los siguientes devolvería en un error del compilador:boolean x = true == 3; // DOES NOT COMPILE boolean y = false != "Giraffe"; // DOES NOT COMPILE boolean z = 3 == "Kangaroo"; // DOES NOT COMPILE
Si se observa el siguiente fragmento:
boolean y = false;
boolean x = (y = true);
System.out.println(x); // Outputs true
Para la comparación de objetos, el operador de igualdad se aplica a las referencias a estos objetos, no a los objetos a los que apuntan. Dos referencias son iguales si y solo si apuntan a lo mismo objeto, o ambos apuntan a nulo. Si se ven algunos ejemplos se entenderá mejor:
File x = new File("myFile.txt");
File y = new File("myFile.txt");
File z = x;
System.out.println(x == y); // Outputs false
System.out.println(x == z); // Outputs true
En el Capítulo 3, "Core Java APIs", se continuará la discusión sobre la igualdad de objetos introduciendo lo que significa que dos objetos diferentes sean equivalentes. También se tratará la igualdad de los String y se mostrará cómo este puede ser un tema no trivial.
4.5. Comprender las sentencias de Java
Los operadores Java permiten crear muchas expresiones complejas, pero están limitadas en la manera
en que pueden controlar el flujo del programa. Por ejemplo, imaginar que se quiere una sección de código
que solo sea ejecutado bajo ciertas condiciones que no pueden ser evaluadas hasta que no se ejecute.
O si se desea que un segmento particular de código se repita una vez por cada elemento en alguna lista.
Como se dijo en el Capítulo 1, una declaración de Java es una unidad completa de ejecución en Java,
terminando con un punto y una coma (;). En el capítulo, se mostrarán varias declaraciones de control
de flujo en Java. Las declaraciones de control de flujo rompen el flujo de ejecución mediante la toma de
decisiones, el bucle y la ramificación, permitiendo que la aplicación seleccione segmentos particulares
del código para ejecutar.
Las declaraciones se pueden aplicar a expresiones simples, o a un bloque de código. Un bloque de código
en Java es un grupo de cero o más declaraciones entre llaves, ({}), y se puede usar en cualquier lugar
donde se permita usar una declaración simple.
4.5.1. if-then
De vez en cuando, solo se quiere ejecutar un bloque de código según ciertas condiciones. El if-then, como se muestra en el código siguiente, permite que la aplicación ejecute un bloque particular de código si y solo si una expresión booleana se evalúa como verdadera en tiempo de ejecución.
if(booleanExpression){
//Branch if true }
if(hourOfDay < 11)
System.out.println(“Good Morning”);
if(hourOfDay < 11){
System.out.println(“Good Morning”);
morningGreetingCount++;
}
if(hourOfDay < 11)
System.out.println("Good Morning");
morningGreetingCount++;
4.5.2. if-then-else
Se va a complicar el ejemplo anterior, ¿qué pasaría si se quisiera mostrar otro mensaje cuando la hora sea mayor o igual a 11?
if(hourOfDay < 11) {
System.out.println("Good Morning");
}
if(hourOfDay >= 11) {
System.out.println("Good Afternoon");
}
if(booleanExpression){
// Branch if true
} else {
// Branch if false
}
if(hourOfDay < 11) {
System.out.println("Good Morning");
} else {
System.out.println("Good Afternoon");
}
if(hourOfDay < 11) {
System.out.println("Good Morning");
}else if(hourOfDay < 15) {
System.out.println("Good Afternoon");
}else{
System.out.println("Good Evening");
}
if(hourOfDay < 15) {
System.out.println("Good Afternoon");
} else if(hourOfDay < 11) {
System.out.println("Good Morning"); // UNREACHABLE CODE
} else {
System.out.println("Good Evening");
}
a. Verificando si la sentencia if se evalúa en una expresión booleana Echar un vistazo a las siguientes líneas de código:
int x = 1;
if(x) {
// DOES NOT COMPILE ...
}
int x = 1; if(x = 5) { // DOES NOT COMPILE ...
}
4.5.3. Operador Ternario
Ahora que se ha visto las declaraciones if-then-else, se puede volver brevemente a la discusión de los operadores y presentar al último operador. El operador condicional,? :, también conocido como operador ternario, es el único operador que utiliza tres operandos y tiene la forma: booleanExpression? expression1 : expression2
El primer operando debe ser una expresión booleana, y el segundo y el tercero pueden ser cualquier expresión que devuelva un valor. La operación ternaria es realmente una forma condensada de un ifthen- else que devuelve un valor. Por ejemplo, los siguientes dos fragmentos de código son equivalentes:
int y = 10;
final int x;
if(y > 5) {
x = 2 * y; }
else { x =
3 * y; }
int y = 10;
int x = (y > 5)? (2 * y) : (3 * y);
System.out.println((y > 5)? 21 : "Zebra");
int animal = (y < 91)? 9 : "Horse"; // DOES NOT COMPILE
a. Evaluación de las expresiones ternarias A partir de Java 7, solo una de las expresiones de la derecha del operador ternario será evaluado en tiempo de ejecución. De manera similar a los operadores de cortocircuito, si una de las dos expresiones de la derecha del operador ternario realiza un efecto secundario, entonces no se puede aplicar en tiempo de ejecución. Vamos a ilustrar este principio con el siguiente ejemplo: int y = 1; int z = 1; final int x = y<10? y++ : z++; System.out.println(y+","+z); // Outputs 2,1 Tener en cuenta que como la parte de la izquierda de la expresión es verdadera solo se incrementa y. Contrástar con el siguiente ejemplo:
### 4.5.4. switch
switch(variableToTest) { case
constantExpression1: // Branch
for case1; break; case
constantExpression2: // Branch
for case2; break;
...
default:
}
- int y Integer
- byte y Byte
- short y Short
- char y Character
- String
- Valores enum
System.out.println("Sunday");
break; case 6:
System.out.println("Saturday");
break;
}
Con el valor de dayOfWeek de 5 el código devolverá “Weekday”.
Lo primero que se puede notar es que hay una sentencia break al final de cada case y la sección
predeterminada(default). Se discutirá las sentencias break en detalle cuando se vean los bucles, pero
por ahora, todo lo que se necesita saber es que finaliza la sentencia switch y el control de flujo vuelve a
la sentencia adjunta. Como se verá pronto, si se omite la declaración del break, el flujo continuará hasta
el siguiente caso en curso o bloque predeterminado.
Otra cosa que se puede notar es que el bloque predeterminado no está al final del switch. No es un
requisito que el caso o las declaraciones predeterminadas estén en un orden en particular, a menos que
tenga vías que lleguen a múltiples secciones del bloque switch en una sola ejecución.
Para ilustrar lo aprendido se considerará la siguiente variación:
int dayOfWeek = 5;
switch(dayOfWeek) {
case 0:
System.out.println("Sunday");
default:
System.out.println("Weekday"); case
6 :
System.out.println("Saturday");
break;
}
Sunday
Weekday
Saturday
private int getSortOrder(String firstName, final String lastName) {
String middleName = "Patricia"; final String suffix = "JR"; int
id = 0; switch(firstName){ case "Test": return 52;
case middleName: // DOES NOT COMPILE id = 5;
### 4.5.5. while
while(booleanExpression){
//Body
}
Como se muestra en el código, un bucle while es similar a las sentencias if-then ya que está compuesta
por una expresión booleana e instrucciones o bloque de instrucciones. Durante la ejecución, la expresión
booleana es evaluada antes de cada iteración del bucle y termina si la evaluación devuelve un false. Es
importante darse cuenta que el bucle while puede terminar después de su primera evaluación de la
expresión booleana. De esta forma el bloque de instrucciones puede no ejecutarse nunca.
Si se vuelve al ejemplo de ratón del capítulo 3 y se muestra un bucle que puede ser utilizado para
modelar un ratón comiendo una comida:
int x = 2; int
y = 5; while(x
< 10) y++;
### 4.5.6. do-while
do{
//Body
}while(booleanExpression);
La principal diferencia entre la estructura del do-while y del while es que ordena intencionadamente las
instrucciones o los bloques de instrucciones antes de la expresión condicional, para recalcar que la
instrucción será ejecutada antes de evaluar la expresión. Por ejemplo, mirar la salida del siguiente
código:
int x = 0;
do {
x++;
}while(false);
System.out.println(x); // Outputs 1
Java ejecutará primero el bloque de instrucciones, y luego comprobará la condición del bucle. A pesar de
que el bucle termina inmediatamente, el bloque de instrucciones se ejecuta una vez y el programa
devuelve 1.
while(x > 10)
{ x--; }
if(x > 10) {
do { x--;
}while(x > 10);
}
Aunque uno de los bucles es más fácil de leer, son funcionalmente iguales. Java recomienda utilizar los
bucles while cuando no sea necesario ejecutar sus instrucciones, y utilizar los bucles do-while cuando
sea imprescindible que se ejecute como mínimo una vez, pero, en la práctica, elegir entre uno u otro es
algo personal.
Por ejemplo, pese a que la primera declaración es más corta, la segunda tiene una ventaja que permite
hacer uso de la sentencia if-then y realizar otras operaciones en la rama del else, como se muestra en
el ejemplo:
### 4.5.7. La sentencia for
for(initialization; booleanExpression; updateStatement) {
// Body
}
El código puede parecer algo confusa y arbitraria al principio, la organización de los componentes y el
flujo permite crear poderosas sentencias en poco espacio al contrario de otros bucles que necesitarían
múltiples líneas. Fijarse que cada sección está separada por punto y coma (;) y la inicialización y la
actualización pueden contener varias sentencias separadas por comas.
Las variables creadas en el bloque de inicialización tienen un ámbito limitado y solo serán accesibles
dentro del bucle for. Alternativamente, las variables declaradas antes del for y modificadas en el bloque
de inicialización pueden ser utilizadas fuera del bucle for ya que su ámbito es anterior a la creación del
bucle for.
A continuación, este ejemplo imprime en pantalla los números del 0 al 9:
for(int i = 0; i < 10; i++) {
System.out.print(i + " ");
}
0 1 2 3 4 5 6 7 8 9
- Creación de un bucle infinito
for( ; ; ) {
System.out.println("Hello World");
}
- Adición de varios términos a la sentencia for
int x = 0;
for(long y = 0, z = 4; x < 5 && y < 10; x++, y++) {
System.out.print(y + " ");
}
System.out.print(x);
0 1 2 3 4
- Re-declarando una variable en el bloque de inicialización
int x = 0;
for(long y = 0, x = 4; x < 5 && y < 10; x++, y++) { // DOES NOT COMPILE
System.out.print(x + " ");
}
Este ejemplo parece similar al anterior, pero no compila debido al bloque de inicialización. La diferencia
es que x se repite en el bloque de inicialización después de haber sido declarado ya antes del loop, dando
lugar a que el compilador se detenga debido a una declaración de variable duplicada. Se puede fijar este
bucle cambiando la declaración de x y y como sigue:
int x = 0; long
y = 10;
for(y = 0, x = 4; x < 5 && y < 10; x++, y++) {
System.out.print(x + " ");
}
Tener en cuenta que esta variación si compilará porque el bloque de inicialización simplemente asigna
un valor a x y no lo declara.
- Utilizando tipos de datos incompatibles en el bloque de inicialización
for(long y = 0, int x = 4; x < 5 && y<10; x++, y++) { // DOES NOT COMPILE
System.out.print(x + " ");
}
- Usando variables del bucle fuera de este
for(long y = 0, x = 4; x < 5 && y < 10; x++, y++) {
System.out.print(y + " ");
}
System.out.print(x); // DOES NOT COMPILE
### 4.5.8. La sentencia for-each
for(datatype instance : collection){
//Body
}
final String[] names = new String[3]; names[0] = "Lisa";
names[1] = "Kevin"; names[2] = "Roger"; for(String name : names)
{ System.out.print(name + ", ");
}
java.util.List<String> values = new java.util.ArrayList<String>();
values.add("Lisa"); values.add("Kevin"); values.add("Roger"); for(String value
: values) { System.out.print(value + ", ");
}
String names = "Lisa";
for(String name : names) { // DOES NOT COMPILE
System.out.print(name + " ");
}
En este ejemplo, el String names no es un array y no implementa la clase java.lang.iterable, así que el
compilador lanzará una excepción ya que no sabe como iterar un String.
String[] names = new String[3]; for(int name : names) { // DOES NOT COMPILE
System.out.print(name + " ");
}
Este código no compilará porque en el lado izquierdo del bucle no se define una instancia de String.
Nótese que, en este último ejemplo, el array se inicializa con tres valores de puntero cero. En sí mismo,
eso no causará un fallo de compilación, sólo imprimirá tres veces cero.
for(String name : names) { System.out.print(name + ", ");
}
for(int i=0; i < names.length; i++) {
String name = names[i];
System.out.print(name + ", ");
}
for(int value : values) { System.out.print(value + ", ");
}
for(java.util.Iterator<Integer> i = values.iterator(); i.hasNext(); ) { int value =
i.next();
System.out.print(value + ", ");
}
Lisa, Kevin, Roger,
Lisa, Kevin, Roger
- 5, 10,
## 4.6. Comprendiendo el control de flujo avanzado
### 4.6.1. Bucles anidados
int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}}; for(int[] mySimpleArray :
myComplexArray) { for(int i=0; i<mySimpleArray.length; i++) {
System.out.print(mySimpleArray[i]+"\t");
}
System.out.println();
}
5 2 1 3
3 9 8 9
5 7 12 7
int x = 20;
while(x>0) {
do { x -=
2 }while
(x>5); x--;
System.out.print(x+"\t");
}
La primera vez que este bucle se ejecuta, el bucle interno se repite hasta que el valor de x es 4. El valor
será entonces decrementado a 3 y será la salida, al final de la primera iteración del bucle exterior. En la
segunda iteración del bucle exterior, el do-while interno se ejecutará una vez, aunque x no sea mayor
que 5. Recordar que las sentencias do-while siempre se ejecutan al menos una vez. Esto reducirá el valor
a 1, que será decrementado aún más por el operador de decremento en el bucle exterior a 0. Una vez
que el valor alcance 0, el bucle externo se termina. El resultado es que el código emitirá lo siguiente:
3 0
### 4.6.2. Añadiendo etiquetas opcionales
int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}}; OUTER_LOOP: for(int[]
mySimpleArray : myComplexArray) {
INNER_LOOP: for(int i=0; i<mySimpleArray.length; i++) {
System.out.print(mySimpleArray[i]+"\t");
}
System.out.println();
}
### 4.6.3. La declaración break
public class SearchSample { public static
void main(String[] args) { int[][] list =
{{1,13,5},{1,2,5},{2,7,2}};
Value 2 found at: (1,1)
if(list[i][j]==searchValue) { positionX = i; positionY =
j; break;
}
¿Cómo cambiaría esto la salida? En lugar de salir cuando se encuentra el primer valor que coincida, el
programa sólo saldrá del bucle interno cuando se cumpla la condición. En otras palabras, la estructura
ahora encontrará el primer valor que se ajuste del último bucle interno que contenga el valor, resultando
en la siguiente salida:
Value 2 found at: (2,0)
if(list[i][j]==searchValue) {
positionX = i;
positionY = j;
}
Value 2 found at: (2,2)
### 4.6.4. La sentencia continue
Se puede notar que la sintaxis de la declaración continue refleja la declaración break. De hecho, las
sentencias son similares en cuanto a su uso, pero con resultados diferentes. Mientras que la sentencia
break transfiere el control a la sentencia adjunta, la sentencia continue transfiere el control a la expresión
booleana que determina si el bucle debe continuar. En otras palabras, termina la iteración actual del
bucle. También, al igual que la declaración break, la declaración continue se aplica al bucle interno más
cercano en ejecución usando instrucciones de etiqueta opcionales para anular este comportamiento.
Ejemplo:
public class SwitchSample {
public static void main(String[] args) {
FIRST_CHAR_LOOP: for (int a = 1; a <= 4; a++) { for (char x = 'a'; x <= 'c'; x++)
{ if (a == 2 || x == 'b') continue FIRST_CHAR_LOOP;
System.out.print(" " + a + x);
}
}
}
}
1a 3a 4a
1a 1c 3a 3c 4a 4c
1a 1b 1c 2a 2b 2c 3a 3b 3c 4a 4b 4c
(^) Permite etiquetas
opcionales
Permite
sentencias break
Permite
sentencias
continue
if Si No No
while Si Si Si
do while Si Si Si
for Si Si Si
switch Si Si No
### 4.6.1. Resumen
- Cómo utilizar todos los operadores Java requeridos que se describen.
- Saber cómo influye la precedencia del operador en la forma en que se interpreta una expresión
determinada.
- Los operadores de asignación son operadores binarios que modifican la variable con el valor del lado
derecho de la ecuación.
- El “casting” es necesario siempre que se pase de un dato numérico más grande a un tipo de datos
numéricos más pequeños, o la conversión de un número float a un valor int.
- Los operadores complejos son operadores de asignación con una operación aritmética o lógica
incorporada que se aplican de izquierda a derecha de la expresión y almacena el valor resultante en la
variable de la parte izquierda de la pantalla.
- Los operadores relacionales son aquellos que comparan dos expresiones y devuelven un valor booleano.
- Los operadores lógicos, (&), (|) y (^), se pueden aplicar a datos de tipo numéricos y booleanos.
- Los operadores de igualdad comparan dos operandos y devuelven un valor booleano si las expresiones
o valores son iguales, o no iguales, respectivamente.
- Las estructuras de control: las estructuras de control de la toma de decisiones, incluidas las de tipo
ifthen, if-then-else y switch, así como las estructuras de control de la repetición, incluidas for, for-each,
while y do-while.
- La mayoría de estas estructuras requieren la evaluación de una expresión booleana en particular, ya
sea para las decisiones de ramificación o una vez por repetición.
- La sentencia switch es la única que soporta una variedad de tipos de datos, incluyendo variables String
a partir de Java 7.
- Con un for-each no es necesario escribir explícitamente una expresión booleana, ya que el compilador
las construye implícitamente. Para mayor claridad, se refiere a un bucle for mejorado como un bucle
foreach, pero sintácticamente están escritos como una declaración for.