TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
1. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Jaaaaaaaaaaaa
Desarrollo de Aplicaciones Web con J2EE
2. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
TEMA Nº 8: CONTROL DE EJECUCIÓN Y
MANTENIMIENTO DE SESIÓN
Control de ejecución
- true y false
- if - else
- Iteración
- do - while
- for
- El operador coma
- Sintaxis foreach
- return
- break y continue
- La despreciada instrucción "goto"
- switch
Al igual que las criaturas sensibles, un programa debe manipular su mundo y tomar decisiones durante la
ejecución. En Java, las decisiones se toman mediante las instrucciones de control de ejecución.
En este tema vamos a ver las instrucciones de control de ejecución.
TRUE Y FALSE
Todas las instrucciones condicionales utilizan la veracidad o la falsedad de una expresión condicional para
seleccionar una ruta de ejecución. Es decir, se compararán una serie de valores mediante los operadores
relacionales y dependiendo del resultado (true o false) la ejecución irá por un camino u otro.
IF - ELSE
Esta instrucción es la forma más básica de controlar el flujo de un programa. La opción else es opcional,
tendríamos:
if(expresión - booleana)
instrucción
o
if(expresión - booleana)
instrucción1
else
instrucción2
3. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
La expresión - booleana producirá un valor true o false. En el primer caso si es true, pasará a ejecutar la
instrucción o instrucciones (si son varias, encerradas entre llaves {}) en caso contrario no hará nada. En el
segundo caso si se cumple la expresión - booleana ejecutará la instrucción o instrucciones instrucción1, si no
se cumple se ejecutará la instrucción o instrucciones instrucción2. Vamos a ver un ejemplo:
//: control/IfElse.java
importstaticnet.mindview.util.Print.*;
publicclassIfElse {
staticintresult = 0;
staticvoidtest(inttestval, inttarget) {
if(testval > target)
result = +1;
elseif(testval < target)
result = -1;
else
result = 0; // Match
}
publicstaticvoidmain(String[] args) {
test(10, 5);
print(result);
test(5, 10);
print(result);
test(5, 5);
print(result);
}
} /* Output:
1
-1
0
*//:~
En el método test() podemos ver una instrucción "else if" ya que dentro de un if puede haber varias
comparaciones, el "else" final se ejecutaría en caso de que no se cumplieran ninguna de las condiciones
anteriores.
ITERACIÓN
Para los bucles de ejecución tenemos while, do - while y for, también llamadas instrucciones de iteración. Un
bucle while sería:
while(expresión - booleana)
instrucción
La expresión - booleana se comprueba cuando la ejecución llega al bucle, en caso de que se cumpla, se
ejecuta la o las instrucciones, cada vez que se ejecutan estas instrucciones se vuelve a comprobar si se sigue
cumpliendo la expresión - booleana. Se ejecutan instrucciones mientras se cumpla la expresión - booleana.
Vamos a ver un ejemplo, generamos números aleatorios hasta que se cumpla una determinada condición.
4. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
//: control/WhileTest.java
// Demonstrates the while loop.
publicclassWhileTest {
staticbooleancondition() {
booleanresult = Math.random() < 0.99;
System.out.print(result + ", ");
returnresult;
}
publicstaticvoidmain(String[] args) {
while(condition())
System.out.println("Inside 'while'");
System.out.println("Exited 'while'");
}
} /* (Execute to see output) *///:~
En el método condition() el método random() genera un valor double comprendido entre 0 y 1 (incluye 0, pero
no
1). La variable result es el resultado de una operación de comparación < que genera un boolean. En main
tenemos un bucle while que se va a repetir mientras la variable result del método condition() sea true. Si no lo
véis claro con este ejercicio lo he modificado un poco para que veáis cuando se deja de cumplir que
Math.random()<0.99:
//: control/WhileTest2.java
// Demonstrates the while loop.
publicclassWhileTest2 {
staticbooleancondition() {
booleanresult=true;
doublecentinela=Math.random();
System.out.println("Valor aleatorio: "+centinela);
if(centinela<0.99)
result=true;
else
result=false;
System.out.print(result+", ");
returnresult;
}
publicstaticvoidmain(String[] args) {
while(condition())
System.out.println("Inside 'while'");
System.out.println("Exited 'while'");
}
} /* (Execute to see output) *///:~
5. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
DO - WHILE
El bucle do - while tiene la forma:
do
instrucción
while(expresión - booleana)
Este bucle se ejecuta al menos una vez a diferencia del bucle while. La instrucción o instrucciones que están
entre do y while se ejecutan una vez y posteriormente se evalúa la expresión - booleana, si es true se vuelven
a ejecutar la instrucción o instrucciones y si es false salimos del bucle.
FOR
Es quizá el bucle más utilizado. Tiene la forma:
for(inicialización; expresión - booleana; paso)
Instrucción
Tenemos una inicialización de una variable que utilizaremos como centinela o contador. En la expresión -
booleana comprobamos mediante una expresión condicional si esa variable ha alcanzado un valor
determinado y el paso es el aumento o disminución que hacemos de la variable inicial. Cualquiera de las
expresiones inicialización, expresión - booleana o paso puede estar vacía. La expresión - booleana se
comprueba antes de cada iteración y la instrucción o instrucciones se ejecutarán mientras ésta sea true,
cuando sea false saldremos del bucle. Cada vez que se ejecutan las instrucciones la variable de paso
aumenta o disminuye. El bucle for se repite mientras se cumpla la expresión - booleana.
Vamos a ver un ejemplo:
//: control/ListCharacters.java
// Demonstrates "for" loop by listing
// all the lowercase ASCII letters.
publicclassListCharacters {
publicstaticvoidmain(String[] args) {
for(charc = 0; c < 128; c++)
if(Character.isLowerCase(c))
System.out.println("value: "+ (int)c +
" character: "+ c);
}
} /* Output:
value: 97 character: a
value: 98 character: b
value: 99 character: c
value: 100 character: d
value: 101 character: e
value: 102 character: f
value: 103 character: g
value: 104 character: h
value: 105 character: i
value: 106 character: j
...
*///:~
6. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Vemos que hay un bucle for en el que se inicializa la variable c, cuyo ámbito se restringe al bucle for. La
expresión - booleana que se comprueba es c<128 y el paso es c++, la variable c aumenta en uno en cada
iteración. Este bucle se repetirá 128 veces.
Se utiliza la clase envoltorio java.lang.Character, que permite tratar una variable char como un objeto. El
método Character.isLowerCase(c) comprueba si el carácter c es una letra minúscula.
Mientras que en C las variables se definen al principio de un bloque para reservar la memoria necesaria, en
Java se puede definir una variable en el lugar en que se necesite.
EL OPERADOR COMA
El operador coma sólo se utiliza en la expresión de control de un bucle for. Tanto en la parte de la
inicialización como en la parte correspondiente al paso de la expresión de control, se pueden incluir
instrucciones separadas por comas que serán evaluadas secuencialmente. Podemos definir dentro de la
instrucción for múltiples variables, todas deben ser del mismo tipo:
//: control/CommaOperator.java
publicclassCommaOperator {
publicstaticvoidmain(String[] args) {
for(inti = 1, j = i + 10; i < 5; i++, j = i * 2) {
System.out.println("i = "+ i + " j = "+ j);
}
}
} /* Output:
i = 1 j = 11
i = 2 j = 4
i = 3 j = 6
i = 4 j = 8
*///:~
El int de la instrucción for es tanto para i como para j. La parte de la inicialización puede tener cualquier
número de definiciones de un mismo tipo. Definir variables en una expresión de control está limitada a los
bucles for. Tanto en la inicialización como en la parte de paso las instrucciones se evalúan secuencialmente.
SINTAXIS FOREACH
Se trata de una sintaxis for nueva para utilizarla con matrices y contenedores (lo veremos más adelante). Con
la sintaxis foreach (para todos) no es necesario crear una variable int para efectuar un recuento a través de
una secuencia de elementos, el bucle for genera cada elemento automáticamente.
En el siguiente ejemplo tenemos una matriz de float y queremos seleccionar cada elemento de la matriz:
//: control/ForEachFloat.java
importjava.util.*;
publicclassForEachFloat {
publicstaticvoidmain(String[] args) {
Random rand = newRandom(47);
floatf[] = newfloat[10];
for(inti = 0; i < 10; i++)
f[i] = rand.nextFloat();
for(floatx : f)
System.out.println(x);
}
} /* Output:
0.72711575
7. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
0.39982635
0.5309454
0.0534122
0.16020656
0.57799757
0.18847865
0.4170137
0.51660204
0.73734957
*///:~
La matriz se rellena con un antiguo bucle for. La sintaxis foreach es de la forma:
for(floatx:f)
Mediante esta expresión definimos una variable x de tipo float y asignamos secuencialmente cualquier
elemento de f a x.
Cualquier método que devuelve una matriz es un buen candidato para emplearlo con la sintaxis foreach.
Vamos a verlo con un ejemplo:
//: control/ForEachString.java
publicclassForEachString {
publicstaticvoidmain(String[] args) {
for(charc : "An African Swallow".toCharArray() )
System.out.print(c + " ");
}
} /* Output:
A n A f r i c a n S w a l l o w
*///:~
El método toCharArray() devuelve una matriz de char, como vemos la salida de este método puede ser
utilizada con la sintaxis foreach.
Esta sintaxis funciona con cualquier objeto de tipo Iterable (lo veremos más adelante).
Muchas instrucciones for requieren ir paso a paso a través de una secuencia de valores enteros:
for(inti=0;i<100;i++)
Para este tipo de instrucciones la sintaxis foreach no funcionará a menos que creemos primero una matriz de
valores int. Para simplificar esta tarea el autor ha creado un método range() en net.mindview.util.Range que
genera y devuelve la matriz apropiada. La intención es que el método range() se utilice como importación de
tipo static:
//: control/ForEachInt.java
importstaticnet.mindview.util.Range.*;
importstaticnet.mindview.util.Print.*;
publicclassForEachInt {
publicstaticvoidmain(String[] args) {
for(inti : range(10)) // 0..9
printnb(i + " ");
print();
for(inti : range(5, 10)) // 5..9
printnb(i + " ");
print();
for(inti : range(5, 20, 3)) // 5..20 step 3
8. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
printnb(i + " ");
print();
}
} /* Output:
0 1 2 3 4 5 6 7 8 9
5 6 7 8 9
5 8 11 14 17
*///:~
El método range() está sobrecargado por lo que se pueden utilizar diferentes listas de argumentos. La
primera forma sobrecargada, range(10), empieza en 0 y genera valores hasta el extremo superior del rango
sin incluir éste. La segunda forma, range(5,10), comienza con el primer valor y termina en el último valor
menos 1. La tercera forma, range(5,20,3), incluye un valor de paso, realizándose los incrementos según este
valor.
El método range() permite la utilización de foreach en más lugares, sin embargo, es menos eficiente, por lo
que si necesitamos utilizar el programa a la máxima velocidad, conviene que utilicemos un perfilador, que es
una herramienta que mide el rendimiento del código.
El método printnb() es equivalente a System.out.print, es decir, no genera un carácter de nueva línea, todo lo
que escribe lo coloca en la misma línea.
La sintaxis foreach ahorra tiempo a la hora de escribir código, facilita la lectura y comunica perfectamente qué
es lo que estamos tratando de hacer (obtener cada elemento de la matriz), en lugar de cómo lo estamos
haciendo (estoy creando un índice para poder utilizarlo con cada elemento de la matriz).
RETURN
La palabra clave return es un salto incondicional, es decir, es un salto en el flujo de ejecución que se produce
sin realizar previamente comprobación alguna. Esta palabra clave tiene dos objetivos: especifica qué valor
devolverá un método (si no es void) y hace que la ejecución salga del método actual devolviendo ese valor.
Vamos a verlo con un ejemplo:
//: control/IfElse2.java
importstaticnet.mindview.util.Print.*;
publicclassIfElse2 {
staticinttest(inttestval, inttarget) {
if(testval > target)
return+1;
elseif(testval < target)
return-1;
else
return0; // Match
}
publicstaticvoidmain(String[] args) {
print(test(10, 5));
print(test(5, 10));
print(test(5, 5));
}
} /* Output:
1
-1
0
*///:~
9. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Cuando se ejecuta la instrucción return salimos del método.
Si un método devuelve void y no se incluye return, habrá una instrucción return implícita al final de ese
método, así pues no es necesario incluirla. Pero si el método va a devolver cualquier valor distinto de void,
hay que asegurarse de que todas las rutas de ejecución devuelvan un valor.
BREAK Y CONTINUE
Se puede controlar el flujo de un bucle mediante break y continue. Break provoca la salida del bucle sin
ejecutar el resto de instrucciones, mientras que continue detiene la ejecución de la iteración actual y vuelve al
principio del bucle para comenzar con la siguiente iteración. Vamos a ver un ejemplo:
//: control/BreakAndContinue.java
// Demonstrates break and continue keywords.
importstaticnet.mindview.util.Range.*;
publicclassBreakAndContinue {
publicstaticvoidmain(String[] args) {
for(inti = 0; i < 100; i++) {
if(i == 74) break; // Out of for loop
if(i % 9!= 0) continue; // Next iteration
System.out.print(i + " ");
}
System.out.println();
// Using foreach:
for(inti : range(100)) {
if(i == 74) break; // Out of for loop
if(i % 9!= 0) continue; // Next iteration
System.out.print(i + " ");
}
System.out.println();
inti = 0;
// An "infinite loop":
while(true) {
i++;
intj = i * 27;
if(j == 1269) break; // Out of loop
if(i % 10!= 0) continue; // Top of loop
System.out.print(i + " ");
}
}
} /* Output:
0 9 18 27 36 45 54 63 72
0 9 18 27 36 45 54 63 72
10 20 30 40
*///:~
Recuerda que el método range(100) devuelve una matriz de valores entre 0 y 99. Tanto en el primer bucle for,
como en el segundo que utiliza foreach cuando el valor de i llega a 74 finaliza el bucle (break), no alcanza el
100. Y cuando el resto de la división entre i y 9 es diferente de 0 vuelve al principio del bucle (continue) y
vemos que System.out.print(i+" "); ni siquiera se ejecuta, esta instrucción se ejecutará cuando i sea divisible
por 9 (i%9==0). Luego tenemos un bucle while infinito del que salimos cuando j=1269 (break) y cuando el
resto de dividir i por 10 es diferente de 0 volvemos al principio del bucle (continue). Las instrucciones que
están por debajo de break y continue no se ejecutan.
Un bucle infinito también se puede poner de la forma for(;;).
10. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
LA INSTRUCCIÓN "GOTO"
La instrucción goto ha estado presente en muchos lenguajes de programación desde el principio de la
Informática. Goto representó el origen de las técnicas de control de programa en los lenguajes
ensambladores: "Si se cumple A salta aquí, en caso contrario salta allí".
Una instrucción goto es un salto en el nivel de código fuente, de ahí su mala reputación. ¿No hay una manera
de reorganizar el código para que flujo de control no tenga que dar saltos? Edsger Dijkstra publicó el artículo
"Goto considered harmful" en el que se cuestionó esta instrucción, desde entonces esta instrucción ha sido
despreciada por muchos programadores.
Sin embargo, el problema no es el uso del goto sino su abuso. En determinadas ocasiones incluso su uso es
la mejor opción.
Goto es una palabra reservada en Java pero no se utiliza. Hay dos instrucciones que se utilizan para salir de
una iteración y que se asemejan a un salto, son break y continue. Estas instrucciones se asocian a goto
porque utilizan la misma técnica: una etiqueta.
Una etiqueta es un identificador seguido de dos puntos:
etiqueta1:
La etiqueta se coloca justo ntes de una instrucción de iteración. La única razón para utilizar una etiqueta es si
vamos a anidar otra iteración o una instrucción switch (que veremos después). Si las etiquetas break y
continue interrumpen el bucle actual, cuando se las usa como etiqueta interrumpen todos los bucles hasta el
lugar donde la etiqueta se haya definido:
etiqueta1:
iteración - externa{
iteración - interna{
//...
break; // (1)
//...
continue; // (2)
//...
continueetiqueta1; // (3)
//...
breaketiqueta1; // (4)
}
}
En (1) salimos de la iteración interna y acabamos en la externa. En (2) volvemos al principio de la iteración
interna. En (3) nos salimos tanto de la iteración interna como de la externa y nos situamos en etiqueta1, a
continuación continúa con la iteración pero comenzando por la iteración externa. En (4) nos salimos de las
dos iteraciones, nos situamos en etiqueta1 pero no volvemos a entrar en la iteración, las dos iteraciones han
finalizado. Veamos un ejemplo:
//: control/LabeledFor.java
// For loops with "labeled break" and "labeled
continue."
importstaticnet.mindview.util.Print.*;
publicclassLabeledFor {
publicstaticvoidmain(String[] args) {
inti = 0;
outer: // Can't have statements here
for(; true;) { // infinite loop
inner: // Can't have statements here
for(; i < 10; i++) {
print("i = "+ i);
11. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
if(i == 2) {
print("continue");
continue;
}
if(i == 3) {
print("break");
i++; // Otherwise i never
// gets incremented.
break;
}
if(i == 7) {
print("continue outer");
i++; // Otherwise i never
// gets incremented.
continueouter;
}
if(i == 8) {
print("break outer");
breakouter;
}
for(intk = 0; k < 5; k++) {
if(k == 3) {
print("continue inner");
continueinner;
}
}
}
}
// Can't break or continue to labels here
}
} /* Output:
i = 0
continue inner
i = 1
continue inner
i = 2
continue
i = 3
break
i = 4
continue inner
i = 5
continue inner
i = 6
continue inner
i = 7
continue outer
i = 8
break outer
*///:~
12. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Si nos fijamos en el segundo bucle for, cuando i==2, volvemos al principio de este bucle (instrucción
continue). Si i==3 nos salimos del bucle for (instrucción break), antes de salir tenemos que incrementar i ya
que al salirnos con break de este bucle, la variable i no se incrementa y vamos a volver a entrar en este bucle
for, porque el for que está por encima es infinito. Cuando i==7 volvemos al principio de los dos bucles
(continue outer), es necesario también incrementar i, ya que el bucle for interior no realiza el incremento ya
que con esta instrucción vamos al bucle for exterior. Cuando alcanzamos i==8 salimos de los dos bucles for
(instrucción break outer), sin esta instrucción no habría manera de salir del bucle externo desde el bucle
interno ya que el bucle externo es un bucle infinito.
En aquellos casos en los que salir de un bucle implique salir de un método basta con ejecutar return.
Vamos a ver un ejemplo de break y continue con un bucle while:
//: control/LabeledWhile.java
// While loops with "labeled break" and "labeled
continue."
importstaticnet.mindview.util.Print.*;
publicclassLabeledWhile {
publicstaticvoidmain(String[] args) {
inti = 0;
outer:
while(true) {
print("Outer while loop");
while(true) {
i++;
print("i = "+ i);
if(i == 1) {
print("continue");
continue;
}
if(i == 3) {
print("continue outer");
continueouter;
}
if(i == 5) {
print("break");
break;
}
if(i == 7) {
print("break outer");
breakouter;
}
}
}
}
} /* Output:
Outer while loop
i = 1
continue
i = 2
i = 3
continue outer
Outer while loop
i = 4
i = 5
13. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
break
Outer while loop
i = 6
i = 7
break outer
*///:~
Cuando i==1 vuelve al principio del bucle while interior (instrucción continue). Si i==3 volvemos a la etiqueta
outer (instrucción continue outer), a continuación entramos en los dos bucles while. Cuando i==5 nos salimos
del bucle while interior (instrucción break). Si i==7 nos salimos del bucle while interior y exterior (instrucción
break outer), es decir nos salimos de todos los bucles hasta el que tiene la etiqueta, incluyendo este último.
En Java las etiquetas solo se utilizan si tenemos bucles anidados y queremos ejecutar las instrucciones break
o continue a través de más de un nivel.
SWITCH
Esta instrucción permite seleccionar entre diferentes fragmentos de código basándose en el valor de una
expresión entera. Su forma es:
switch(selector - entero){
casevalor - entero1 : instrucción; break;
casevalor - entero2 : instrucción; break;
casevalor - entero3 : instrucción; break;
casevalor - entero4 : instrucción; break;
//...
default: instrucción;
}
Selector - entero es una expresión que genera un valor entero. Switch compara selector - entero con cada
valor - entero. Si hay coincidencia se ejecuta la correspondiente instrucción (una instrucción o varias). Si no
hay ninguna coincidencia se ejecuta default.
Cada case finaliza con una instrucción break, esto significa que cuando haya una coincidencia del selector -
entero con el valor - entero, se ejecutará la instrucción correspondiente y la ejecución saldrá de switch. Sin
embargo, la instrucción break es opcional. Si no se incluye se ejecutarán las instrucciones case situadas a
continuación hasta que haya una instrucción break. Este comportamiento no es el deseado pero puede ser
útil para programadores avanzados. La instrucción default no finaliza con break, aunque si lo consideramos
oportuno lo podemos incluir.
La instrucción switch permite realizar selecciones donde haya que elegir entre diversas rutas de ejecución,
pero requiere de un selector que se evalúe para dar un valor entero como int o char. Si queremos emplear
una cadena de caracteres o un número en coma flotante como selector no funcionará con switch. Vamos a
ver un ejemplo en que se crean letras de manera aleatoria y se determina si son vocales o consonantes:
/: control/VowelsAndConsonants.java
// Demonstrates the switch statement.
importjava.util.*;
importstaticnet.mindview.util.Print.*;
publicclassVowelsAndConsonants {
publicstaticvoidmain(String[] args) {
Random rand = newRandom(47);
for(inti = 0; i < 100; i++) {
intc = rand.nextInt(26) + 'a';
printnb((char)c + ", "+ c + ": ");
14. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
switch(c) {
case'a':
case'e':
case'i':
case'o':
case'u': print("vowel");
break;
case'y':
case'w': print("Sometimes a vowel");
break;
default: print("consonant");
}
}
}
} /* Output:
y, 121: Sometimes a vowel
n, 110: consonant
z, 122: consonant
b, 98: consonant
r, 114: consonant
n, 110: consonant
y, 121: Sometimes a vowel
g, 103: consonant
c, 99: consonant
f, 102: consonant
o, 111: vowel
w, 119: Sometimes a vowel
z, 122: consonant
...
*///:~
Ámbito de los datos
Ámbito es el contexto que tiene un nombre dentro de un programa. El ámbito determina en qué partes del
programa una entidad puede ser usada.
Esto sirve para que se pueda volver a definir una variable con un mismo nombre en diferentes partes del
programa sin que haya conflictos entre ellos.
Si una variable es declarada dentro de un bloque (método/función/procedimiento), ésta será válida solo
dentro de ese bloque y se destruirá al terminar el bloque. Adicionalmente, la variable no podrá verse ni
usarse fuera del bloque (en el exterior del bloque). La variable dentro del bloque es una variable local y solo
tiene alcance dentro del bloque que se creó y sus bloques hijos, pero no en bloques hermanos ni padres, una
variable definida fuera de cualquier bloque es una variable global y cualquier bloque puede acceder a ella y
modificarla.
En el caso de programación orientada a objetos (POO), una variable global dentro de una clase es
llamada variable de instancia, y cada objeto creado con esa clase tiene una. Adicionalmente existen variables
globales que son comunes a un todos los objetos creados con una clase y son llamadas variables de clase.
Hay dos tipos de alcances, el estático que también es llamado lexicográfico, donde el alcance se determina
en tiempo de compilación, mientras que las variables de alcance dinámico se verificara en el hilo de
ejecución.
15. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Ámbito de página
El último ámbito, el ámbito página, tiene que ver exclusivamente con páginas JSP. Objetos con ámbito página
se almacenan en la instancia de javax.servlet.jsp.PageContext asociada a cada página y son accesibles sólo
dentro de la página JSP en el que fueron creados.
Una vez que la respuesta se envía al cliente o la página remite a otros recursos, los objetos ya no estarán
disponibles.
Cada página JSP tiene implícita una referencia a un objeto llamado pageContext que se pueden utilizar para
almacenar y recuperar objetos de ámbito página.
Tienen los mismos métodos getAttribute () y setAttribute () de otros ámbitos, y funcionan de la misma
manera.
Ámbito de petición( Request scope )
Cada vez que un cliente emite una solicitud HTTP, el servidor crea un objeto que implementa la interfaz
javax.servlet.http.HttpServletRequest.
Entre otras cosas, este objeto contiene una colección de pares de atributos clave / valor que se puede utilizar
para almacenar los objetos que cuya vida coincidirá con la vida de la solicitud.
La clave de cada par es una cadena, y el valor puede ser cualquier tipo de objeto. Los métodos para
almacenar y recuperar objetos en su ámbito de aplicación a partir de la solicitud son los siguientes:
public void setAttribute (String nombre, objeto obj);
Objeto público getAttribute (String nombre);
Los atributos de una solicitud pueden ser eliminados mediante el método removeAttribute (), sin embargo,
dado que el alcance de estos atributos está ligada a la de la solicitud, realmente su uso no es tan importante
como lo es para otros ámbitos.
Una vez que el servidor realiza una solicitud y una respuesta devuelve al cliente, la solicitud y de sus atributos
ya no están disponibles para el cliente y puede ser eliminados por el recolector de basura de la JVM.
Los Struts, por ejemplo, proporcionan un marco para permitir almacenar objetos JavaBeans en una solicitud,
a fin de que puedan ser utilizados por los componentes de presentación, tales como las páginas JSP. Esto
hace que sea mucho más fácil de acceder a los datos JavaBeans, sin tener que preocuparse más tarde por
hacer un mantenimiento de limpieza de los objetos.
Rara vez hay una necesidad de eliminar los objetos de alcance de solicitud, el contenedor web se encarga de
eso.
Los objetos almacenados en la solicitud son visibles sólo a los recursos que tienen acceso a esa petición. Una
vez que la respuesta ha sido devuelta al cliente, la visibilidad desaparece y los objetos también.
Objetos que se almacenan en una solicitud no son visibles para cualquier otra solicitud del cliente.
Ámbito de sesión( session scope )
El siguiente nivel de visibilidad es el período de sesiones. El contenedor web crea un objeto que implementa
la interfaz javax.servlet.http.HttpSession para identificar a un usuario a través de múltiples solicitudes de
página.
El cuándo una sesión se crea depende de la aplicación y el contenedor aplicación. La sesión del usuario se
mantendrá por un período de tiempo relacionado con la frecuencia con que el usuario hace peticiones. El
periodo de inactividad es configurable a través del descriptor de aplicación. También se puede destruir la
sesión prematuramente llamando al método invalidate ().
16. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
La sesión también permite definir una colección de objetos que se almacenan en base a un esquema de
pares clave / valor como en el ámbito de la solicitud. La única diferencia entre éste y el proporcionado por la
solicitud es la duración de los objetos. Los objetos de sesión existen a través de múltiples de solicitudes del
cliente.
Los Struts utilizan ampliamente los objetos de sesión. Un ejemplo son los objetos asociados al usuario
visibles desde todo el framework.
Los objetos almacenados en una sesión de usuario no son visibles para los usuarios con una sesión diferente.
El contenedor web no proporciona la sincronización de los objetos almacenados en las distintas sesiones que
pueda haber y es responsabilidad del desarrollador la protección de los recursos.
Ámbito de aplicación
Un mayor nivel de visibilidad y duración tienen los objetos almacenados en el ámbito de aplicación.
Objetos de ámbito de aplicación son visibles a todos los clientes y los hilos de la aplicación web. Estos viven
hasta que sean 'eliminados explícitamente' o hasta que se termine la aplicación.
El servlet crea un contenedor de objetos, con interfaz javax.servlet.ServletContext para cada aplicación Web
que está instalado en el contenedor.
Más allá del alcance de la solicitud y el período de sesiones de objetos, la aplicación permite a los objetos
ServletContext ser almacenados y recuperados por la aplicación completa y persistir durante la vida útil de
las solicitud.
Una aplicación que utilice el framework Struts debe almacenar JavaBeans visibles para todos los usuarios.
Normalmente, los objetos son almacenados en este ámbito durante la aplicación de inicio y permanecer allí
hasta que la aplicación termine.
Uso de la sesión
En JSP las acciones que se pueden realizar sobre las sesiones se llevan a cabo mediante la interface
HttpSession y los métodos que implementa. Esta interfaz está incluida dentro delpaquete javax.servlet.http y
es utilizada por el contenedor de páginas JSP para crear una sesión entre el servidor y el cliente.
Para obtener la sesión de un usuario se utiliza el método getSession() que devuelve una interfaz de tipo
HttpSession.
<%
HttpSession sesion=request.getSession();
%>
Una vez creado el objeto de tipo sesión es posible acceder a una serie de datos sobre la misma. Uno de estos
datos es
idSession que devuelve un identificador único asociado a una sesión:
<%
HttpSession sesion=request.getSession(); out.println(“IdSesion: ”+sesion.getId());
%>
Cada intérprete de JSP generará un identificador diferente. Así en el caso del servidor Jakarta-Tomacat3.2.3,
el resultado sería similar a:
17. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Todas las sesiones que se crean tienen asociado un identificador (id) que es posible conocer a través del
método getId ().
Es posible conocer el momento en el que se creó la sesión:
<%@page import=”java.util.*” session=”true” %>
<%
HttpSessionsesion=request.getSession();out.println(“Creación:“+sesion.getCreation
Time());Datemomento=newDate(sesion.getCreationTime());out.println(“<BR>Creación:“
+momento);
%>
En el primer caso se muestra el dato tal cual lo devuelve el método getCreationTime (), que es una fecha en
formato long, mientras que en el segundo caso se formatea para que tenga un aspecto más común.
18. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
A través del método getCreationTime () es posible conocer la Fecha y la hora en que se creó la sesión.
También se puede conocer la fecha y hora de la última vez que el cliente accedió al servidor con el que se
creó la sesión, utilizando el método getLastAccesedTime():
<%
Dateacceso=newDate(sesion.getLastAccessedTime());out.println(“Últimoacceso:“+acce
so+”<br>”);
%>
Teniendo en cuenta el momento en el que se creó la sesión y la última vez que se accedió al servidor, se
puede conocer el tiempo que lleva el cliente conectado al servidor, o lo que es lo mismo el tiempo que lleva
el usuario navegando por la páginas JSP:
<%
longlongDuracion=sesion.getLastAccessedTime()sesion.getCreationTime();
Dateduracion=newDate(longDuracion);out.println(“Duracion:
“+duracion.getMinutes()+”min.”+duracion.getSeconds()+”seg”)
;
%>
19. Desarrollo de Aplicaciones Web con J2EE
Ing. Pablo Cesar Ttito C.
InfomixUnitek@gmail.com
Utilizando el momento en el que se creó la sesión y la última vez accedió se puede llegar a saber el tiempo
que ha estado el usuario visitando nuestras páginas web.
La interfaz HttpSession ofrece el método isNew() mediante el cual es posible saber si la sesión creada es
nueva o se está tomando de una previamente creada:
<%
HttpSessionsesion=request.getSession();out.println(“nueva:“+sesion.isNew());
%>
Si se ejecuta el ejemplo la primera vez el método devolverá true, ya que previamente no había ninguna
sesión y ha sido creada en ese instante. Si se recarga la página devolverá false ya que la sesión ya ha sido
creada.
Las sesiones no necesitan ningún tipo de mantenimiento, una vez creadas no es necesario utilizarlas de
forma obligatoria o tener que refrescar los datos asociados a las mismas, se deben ver como una variable
más con la diferencia que pueden ser utilizadas en cualquier página independientemente del lugar en el que
hayan sido creadas.
Cookies persistentes
Las cookies persistentes se almacenan durante un tiempo establecido por el servidor Web cuando éste pasa
la cookie a Internet Explorer. Estas cookies se utilizan para almacenar información de estado entre las visitas
a un sitio.
Las cookies por sesión almacenan información de estado únicamente dentro de una sesión. Estas cookies
sólo se almacenan en caché mientras un usuario visita el servidor Web que emite la cookie por sesión y se
eliminan de la caché cuando el usuario cierra la sesión.
Las páginas Active Server (ASP) que se ejecutan en Microsoft Internet Information Server 3.0 o posterior
utilizan con frecuencia cookies por sesión. Estas cookies almacenan información de la sesión mientras el
usuario examina varias páginas ASP de un sitio.