Academia.eduAcademia.edu

DAW Programacion Tema 4: Uso de estructuras de control.pdf

TEMA 4 Contenido 1. Introducción ........................................................................................................................................ 1 2. Sentencias y bloques ........................................................................................................................... 3 3. Estructuras de selección ...................................................................................................................... 6 3.1. Estructura if e if‐else .................................................................................................................................... 7 3.2. Estructura switch ......................................................................................................................................... 9 4. Estructuras de repetición .................................................................................................................. 11 4.1. Estructura for ............................................................................................................................................. 11 4.2. Estructura for/in ......................................................................................................................................... 13 4.3. Estructura while ......................................................................................................................................... 14 4.4. Estructura do‐while .................................................................................................................................... 15 5. Estructuras de salto ........................................................................................................................... 17 5.1. Sentencias break y continue ...................................................................................................................... 17 5.2. Etiquetas .................................................................................................................................................... 18 5.3. Sentencia Return ........................................................................................................................................ 19 6. Excepciones ....................................................................................................................................... 21 6.1. Capturar una excepción ............................................................................................................................. 22 EJERCICIO RESUELTO ....................................................................................................................................................................... 23 6.2. El manejo de excepciones .......................................................................................................................... 24 6.3. Delegación de excepciones con throws ..................................................................................................... 25 7. Prueba de programas ........................................................................................................................ 26 7.1. La especificación ........................................................................................................................................ 27 7.2. Pruebas exhaustivas ................................................................................................................................... 27 7.3. Pruebas de Caja Negra o Pruebas Funcionales .......................................................................................... 28 7.4. Pruebas de Caja Blanca o Pruebas Estructurales ....................................................................................... 28 7.5. Otras pruebas ............................................................................................................................................. 29 Sabiduría popular: “Cuatro ojos ven más que dos”. ......................................................................................... 29 7.6. Realización de Pruebas Unitarias con JUnit ............................................................................................... 30 Test con JUnit ..................................................................................................................................................................30 8. Depuración de programas ................................................................................................................. 36 Depuración básica en NetBeans. ...................................................................................................................... 39 9. Documentación del código................................................................................................................ 45 R. Caron.: "do not document bad code ‐ rewrite it" ......................................................................................... 46 9.1 Etiquetas y posición .................................................................................................................................... 46 9.2. Uso de las etiquetas ................................................................................................................................... 47 9.3. Orden de las etiquetas ............................................................................................................................... 48 Documentación de clases con Javadoc ............................................................................................................................................ 49 Diseño de Aplicaciones Web Tema 4 1. Introducción CASO PRÁCTICO Los miembros de BK Programación están inmersos en el mundo de Java, ya conocen una buena parte del lenguaje y ahora van a empezar a controlar el comportamiento de sus programas. María pregunta a Juan: – Dime Juan, ¿En Java también hay condicionales y bucles? –Efectivamente María, como la gran mayoría de los lenguajes de programación, Java incorpora estructuras que nos permiten tomar decisiones, repetir código, etc. Cada estructura tiene sus ventajas e inconvenientes y hay que saber dónde utilizar cada una de ellas. – Aclara Juan. En unidades anteriores has podido aprender cuestiones básicas sobre el lenguaje JAVA: definición de variables, tipos de datos, asignación de valores, uso de literales, diferentes operadores que se pueden aplicar, conversiones de tipos, inserción de comentarios, etc. Posteriormente, nos sumergimos de lleno en el mundo de los objetos. Primero hemos conocido su filosofía, para más tarde ir recorriendo los conceptos y técnicas más importantes relacionadas con ellos: Propiedades, métodos, clases, declaración y uso de objetos, librerías, etc. Vale, parece ser que tenemos los elementos suficientes para comenzar a generar programas escritos en JAVA, ¿Seguro?. REFLEXIONA Piensa en la siguiente pregunta: ¿Cómo un programa puede determinar la aparición en pantalla de un mensaje de ÉXITO o ERROR, según los datos de entrada aportados por un usuario? No son sólo los datos de entrada aportados por un usuario, existen más variables. Sigue con atención la unidad y lo comprenderás. Como habrás deducido, con lo que sabemos hasta ahora no es suficiente. Existen múltiples situaciones que nuestros programas deben representar y que requieren tomar ciertas decisiones, ofrecer diferentes alternativas o llevar a cabo determinadas operaciones repetitivamente para conseguir sus objetivos. Si has programado alguna vez o tienes ciertos conocimientos básicos sobre lenguajes de programación, sabes que la gran mayoría de lenguajes poseen estructuras que permiten a los programadores controlar el flujo de la información de sus programas. Esto realmente es una ventaja para la persona que está aprendiendo un nuevo lenguaje, o tiene previsto aprender más de uno, ya que estas estructuras suelen ser comunes a todos (con algunos cambios de sintaxis o conjunto de reglas que definen las secuencias correctas de los elementos de un lenguaje de programación.). Es decir, si conocías sentencias de control de flujo en otros lenguajes, lo que vamos a ver a lo largo de esta unidad te va a sonar bastante. Para alguien que no ha programado nunca, un ejemplo sencillo le va a permitir entender qué es eso de las sentencias de control de flujo. Piensa en un fontanero (programador), principalmente trabaja con agua (datos) y se encarga de hacer que ésta fluya por donde él quiere (programa) a través de un conjunto de tuberías, codos, latiguillos, llaves de paso, etc. (sentencias de control de flujo). Pues esas estructuras de control de flujo son las que estudiaremos, conoceremos su estructura, funcionamiento, cómo utilizarlas y dónde. A través de ellas, al construir nuestros programas podremos hacer que los datos (agua) fluyan por los caminos adecuados para representar la realidad del problema y obtener un resultado adecuado. ‐1‐ Uso de estructuras de control DAW Los tipos de estructuras de programación que se emplean para el control del flujo de los datos son los siguientes: 9 Secuencia: compuestas por 0, 1 o N sentencias que se ejecutan en el orden en que han sido escritas. Es la estructura más sencilla y sobre la que se construirán el resto de estructuras. 9 Selección: es un tipo de sentencia especial de decisión y de un conjunto de secuencias de instrucciones asociadas a ella. Según la evaluación de la sentencia de decisión se generará un resultado (que suele ser verdadero o falso) y en función de éste, se ejecutarán una secuencia de instrucciones u otra. Las estructuras de selección podrán ser simples, compuestas y múltiples. 9 Iteración: es un tipo de sentencia especial de decisión y una secuencia de instrucciones que pueden ser repetidas según el resultado de la evaluación de la sentencia de decisión. Es decir, la secuencia de instrucciones se ejecutará repetidamente si la sentencia de decisión arroja un valor correcto, en otro la estructura de repetición se detendrá. Además de las sentencias típicas de control de flujo, en esta unidad haremos una revisión de las sentencias de salto, que aunque no son demasiado recomendables, es necesario conocerlas. Como nuestros programas podrán generar errores y situaciones especiales, echaremos un vistazo al manejo de excepciones en JAVA. Posteriormente, analizaremos la mejor manera de llevar a cabo las pruebas de nuestros programas y la depuración de los mismos. Y finalmente, aprenderemos a valorar y utilizar las herramientas de documentación de programas. Vamos entonces a ponernos el mono de trabajo y a coger nuestra caja de herramientas, ¡a ver si no nos mojamos mucho! ‐2‐ Diseño de Aplicaciones Web Tema 4 2. Sentencias y bloques CASO PRÁCTICO Ada valora muy positivamente en un programador el orden y la pulcritud. Organizar correctamente el código fuente es de vital importancia cuando se trabaja en entornos colaborativos, en los que son varios los desarrolladores los que forman los equipos de programación. Por ello, incide en la necesidad de recordar a Juan y María las nociones básicas a la hora de escribir programas. Este epígrafe lo utilizaremos para reafirmar cuestiones que son obvias y que en el transcurso de anteriores unidades se han dado por sabidas. Aunque, a veces, es conveniente recordar. Lo haremos como un conjunto de FAQs: 9 ¿Cómo se escribe un programa sencillo? Si queremos que un programa sencillo realice instrucciones o sentencias para obtener un determinado resultado, es necesario colocar éstas una detrás de la otra, exactamente en el orden en que deben ejecutarse. 9 ¿Podrían colocarse todas las sentencias una detrás de otra, separadas por puntos y comas en una misma línea?, claro que sí, pero no es muy recomendable. Cada sentencia debe estar escrita en una línea, de esta manera tu código será mucho más legible y la localización de errores en tus programas será más sencilla y rápida. De hecho, cuando se utilizan herramientas de programación, los errores suelen asociarse a un número o números de línea. 9 ¿Puede una misma sentencia ocupar varias líneas en el programa?, sí. Existen sentencias que, por su tamaño, pueden generar varias líneas. Pero siempre finalizarán con un punto y coma. 9 ¿En Java todas las sentencias se terminan con punto y coma?, Efectivamente. Si detrás de una sentencia ha de venir otra, pondremos un punto y coma. Escribiendo la siguiente sentencia en una nueva línea. Pero en algunas ocasiones, sobre todo cuando utilizamos estructuras de control de flujo, detrás de la cabecera de una estructura de este tipo no debe colocarse punto y coma. No te preocupes, lo entenderás cuando analicemos cada una de ellas. 9 ¿Qué es la sentencia nula en Java? La sentencia nula es una línea que no contiene ninguna instrucción y en la que sólo existe un punto y coma. Como su nombre indica, esta sentencia no hace nada. 9 ¿Qué es un bloque de sentencias? Es un conjunto de sentencias que se encierra entre llaves y que se ejecutaría como si fuera una única orden. Sirve para agrupar sentencias y para clarificar el código. Los bloques de sentencias son utilizados en Java en la práctica totalidad de estructuras de control de flujo, clases, métodos, etc. La siguiente tabla muestra dos formas de construir un bloque de sentencias. Bloque de sentencias 1 Bloque de sentencias 2 { sentencia1; sentencia2; …; sentenciaN; {sentencia1; sentencia2;...; sentencia N;} } 9 ¿En un bloque de sentencias, éstas deben estar colocadas con un orden exacto? En ciertos casos sí, aunque si al final de su ejecución se obtiene el mismo resultado, podrían ocupar diferentes posiciones en nuestro programa. ‐3‐ Uso de estructuras de control DAW DEBES CONOCER Observa los tres archivos que te ofrecemos a continuación y compara su código fuente. Verás que los tres obtienen el mismo resultado, pero la organización de las sentencias que los componen es diferente entre ellos. Sentencias, bloques y diferentes organizaciones package organizacion_sentencias; /** * * Organización de sentencias secuencial */ public class Organizacion_sentencias_1 { public static void main(String[] args) { System.out.println ("Organización secuencial de sentencias"); int dia=12; System.out.println ("El día es: " + dia); int mes=11; System.out.println ("El mes es: " + mes); int anio=2011; System.out.println ("El anio es: " + anio); } } En este primer archivo, las sentencias están colocadas en orden secuencial. package organizacion_sentencias; /** * * Organización de sentencias con declaración previa * de variables */ public class Organizacion_sentencias_2 { public static void main(String[] args) { // Zona de declaración de variables int dia=10; int mes=11; int anio=2011; System.out.println ("Organización con declaración previa de variables"); System.out.println ("El día es: " + dia); System.out.println ("El mes es: " + mes); System.out.println ("El anio es: " + anio); } } En este segundo archivo, se declaran al principio las variables necesarias. En Java no es imprescindible hacerlo así, pero sí que antes de utilizar cualquier variable ésta debe estar previamente declarada. Aunque la declaración de dicha variable puede hacerse en cualquier lugar de nuestro programa. package organizacion_sentencias; /** * * Organización de sentencias en zonas diferenciadas * según las operaciones que se realicen en el código */ public class Organizacion_sentencias_3 { public static void main(String[] args) { // Zona de declaración de variables int dia; int mes; int anio; String fecha; //Zona de inicialización o entrada de datos dia=10; mes=11; anio=2011; fecha=""; //Zona de procesamiento fecha=dia+"/"+mes+"/"+anio; ‐4‐ Diseño de Aplicaciones Web Tema 4 //Zona de salida System.out.println ("Organización con zonas diferenciadas en el código"); System.out.println ("La fecha es: " + fecha); } } En este tercer archivo, podrás apreciar que se ha organizado el código en las siguientes partes: declaración de variables, petición de datos de entrada, procesamiento de dichos datos y obtención de la salida. Este tipo de organización está más estandarizada y hace que nuestros programas ganen en legibilidad. Construyas de una forma o de otra tus programas, debes tener en cuenta siempre en Java las siguientes premisas: 9 Declara cada variable antes de utilizarla. 9 Inicializa con un valor cada variable la primera vez que la utilices. 9 No es recomendable usar variables no inicializadas en nuestros programas, pueden provocar errores o resultados imprevistos. AUTOEVALUACIÓN Indica qué afirmación es correcta: Para crear un bloque de sentencias, es necesario delimitar éstas entre llaves. Este bloque funcionará como si hubiéramos colocado una única orden. La sentencia nula en Java, se puede representar con un punto y coma sólo en una única línea. Para finalizar en Java cualquier sentencia, es necesario hacerlo con un punto y coma. Todas las afirmaciones son correctas. ‐5‐ Uso de estructuras de control DAW 3. Estructuras de selección CASO PRÁCTICO Juan está desarrollando un método en el que ha de comparar los valores de las entradas de un login y una contraseña hechas desde el teclado, con los valores almacenados en una base de datos. Para poder hacer dicha comparación necesitará utilizar una estructura condicional que le permita llevar a cabo esta operación, incluso necesitará que dicha estructura condicional sea capaz de decidir qué hacer en función de si ambos valores son correctos o no. Al principio de la unidad nos hacíamos esta pregunta: ¿Cómo un programa puede determinar la aparición en pantalla de un mensaje de ÉXITO o ERROR, según los datos de entrada aportados por un usuario?. Esta y otras preguntas se nos plantean en múltiples ocasiones cuando desarrollamos programas. ¿Cómo conseguimos que nuestros programas puedan tomar decisiones? Para comenzar, lo haremos a través de las estructuras de selección. Estas estructuras constan de una sentencia especial de decisión y de un conjunto de secuencias de instrucciones. El funcionamiento es sencillo, la sentencia de decisión será evaluada y ésta devolverá un valor (verdadero o falso), en función del valor devuelto se ejecutará una secuencia de instrucciones u otra. Por ejemplo, si el valor de una variable es mayor o igual que 5 se imprime por pantalla la palabra APROBADO y si es menor, se imprime SUSPENSO. Para este ejemplo, la comprobación del valor de la variable será la sentencia especial de decisión. La impresión de la palabra APROBADO será una secuencia de instrucciones y la impresión de la palabra SUSPENSO será otra. Cada secuencia estará asociada a cada uno de los resultados que puede arrojar la evaluación de la sentencia especial de decisión. PARA SABER MÁS En el lenguaje de programación C, verdadero o falso se representan mediante un literal entero. 0 representará Falso y 1 o cualquier otro valor, representará Verdadero. Como sabes, en Java las variables de tipo booleano (en computación es aquel que puede representar valores de lógica binaria, esto es 2 valores, valores que normalmente representan falso o verdadero) sólo podrán tomar los valores true (verdadero) o false (falso). La evaluación de las sentencias de decisión o expresiones que controlan las estructuras de selección, devolverán siempre un valor verdadero o falso. Las estructuras de selección se dividen en: 1. 2. 3. 4. Estructuras de selección simples o estructura if. Estructuras de selección compuesta o estructura if­else. Estructuras de selección basadas en el operador condicional. Estructuras de selección múltiples o estructura switch. A continuación, detallaremos las características y funcionamiento de cada una de ellas. Es importante que a través de los ejemplos que vamos a ver, puedas determinar en qué circunstancias utilizar cada una de estas estructuras. Aunque un mismo problema puede ser resuelto con diferentes estructuras e incluso, con diferentes combinaciones de éstas. ‐6‐ Diseño de Aplicaciones Web Tema 4 3.1. Estructura if e if­else La estructura if es una estructura de selección o estructura condicional, en la que se evalúa una expresión lógica o sentencia de decisión y en función del resultado, se ejecuta una sentencia o un bloque de éstas. La estructura if puede presentarse de las siguientes formas: Estructura if simple. if (expresión-lógica) sentencia1; if (expresión-lógica) { sentencia1; sentencia2; …; sentenciaN; } Si la evaluación de la expresión‐lógica ofrece un resultado verdadero, se ejecuta la sentencia1 o bien el bloque de sentencias asociado. Si el resultado de dicha evaluación es falso, no se ejecutará ninguna instrucción asociada a la estructura condicional. Estructura if de doble alternativa. if (expresión-lógica) { sentencia1; if (expresión-lógica) …; sentencia1; sentenciaN; else } else { sentencia1; sentencia2; …; sentenciaN; } Si la evaluación de la expresión‐lógica ofrece un resultado verdadero, se ejecutará la primera sentencia o el primer bloque de sentencias. Si, por el contrario, la evaluación de la expresión‐lógica ofrece un resultado falso, no se ejecutará la primera sentencia o el primer bloque y sí se ejecutará la segunda sentencia o el segundo bloque. Haciendo una interpretación cercana al pseudocódigo tendríamos que si se cumple la condición (expresión lógica), se ejecutará un conjunto de instrucciones y si no se cumple, se ejecutará otro conjunto de instrucciones. Hay que tener en cuenta que la cláusula else de la sentencia if no es obligatoria. En algunos casos no necesitaremos utilizarla, pero sí se recomienda cuando es necesario llevar a cabo alguna acción en el caso de que la expresión lógica no se cumpla. En aquellos casos en los que no existe cláusula else, si la expresión lógica es falsa, simplemente se continuarán ejecutando las siguientes sentencias que aparezcan bajo la estructura condicional if. Los condicionales if e if-else pueden anidarse, de tal forma que dentro de un bloque de sentencias puede incluirse otro if o if-else. El nivel de anidamiento queda a criterio del programador, pero si éste es demasiado profundo podría provocar problemas de eficiencia y legibilidad en el código. En otras ocasiones, un nivel de anidamiento excesivo puede denotar la necesidad de utilización de otras estructuras de selección más adecuadas. Cuando se utiliza anidamiento de este tipo de estructuras, es necesario poner especial atención en saber a qué if está asociada una cláusula else. Normalmente, un else estará asociado con el if inmediatamente superior o más cercano que exista dentro del mismo bloque y que no se encuentre ya asociado a otro else. DEBES CONOCER Para completar la información que debes saber sobre las estructuras if e if‐else, observa el siguiente código. En él podrás analizar el programa que realiza el cálculo de la nota de un examen de tipo test. Además de calcular el valor de la nota, se ofrece como salida la ‐7‐ Uso de estructuras de control DAW calificación no numérica de dicho examen. Para obtenerla, se combinarán las diferentes estructuras condicionales aprendidas hasta ahora. Presta especial atención a los comentarios incorporados en el código fuente, así como a la forma de combinar las estructuras condicionales y a las expresiones lógicas utilizadas en ellas. package sentencias_condicionales; /** * * Ejemplos de utilización de diferentes estructuras * condicionales simples, completas y anidamiento de éstas. */ public class Sentencias_condicionales { /*Vamos a realizar el cálculo de la nota de un examen * de tipo test. Para ello, tendremos en cuenta el número * total de pregunta, los aciertos y los errores. Dos errores * anulan una respuesta correcta. * * Finalmente, se muestra por pantalla la nota obtenida, así * como su calificación no numérica. * * La obtención de la calificación no numérica se ha realizado * combinando varias estructuras condicionales, mostrando expresiones * lógicas compuestas, así como anidamiento. * */ public static void main(String[] args) { // Declaración e inicialización de variables int num_aciertos = 12; int num_errores = 3; int num_preguntas = 20; float nota = 0; String calificacion=""; //Procesamiento de datos nota = ((num_aciertos - (num_errores/2))*10)/num_preguntas; if (nota < 5) { calificacion="INSUFICIENTE"; } else { /* Cada expresión lógica de estos if está compuesta por dos * expresiones lógicas combinadas a través del operador Y o AND * que se representa con el símbolo &&. De tal manera, que para * que la expresión lógica se cumpla (sea verdadera) la variable * nota debe satisfacer ambas condiciones simultáneamente */ if (nota >= 5 && nota <6) calificacion="SUFICIENTE"; if (nota >= 6 && nota <7) calificacion="BIEN"; if (nota >= 7 && nota <9) calificacion="NOTABLE"; if (nota >= 9 && nota <=10) calificacion="SOBRESALIENTE"; } //Salida de información System.out.println ("La nota obtenida es: " + nota); System.out.println ("y la calificación obtenida es: " + calificacion); } } ‐8‐ Diseño de Aplicaciones Web Tema 4 AUTOEVALUACIÓN ¿Cuándo se mostrará por pantalla el mensaje incluido en el siguiente fragmento de código? If (numero % 2 == 0); System.out.print(“El número es par /n”); Nunca Siempre Cuando el resto de la división entre 2 del contenido de la variable numero, sea cero. Aunque detrás de la expresión lógica de la estructura if existe un punto y coma, la sentencia que imprime el mensaje en pantalla siempre se ejecutará. 3.2. Estructura switch ¿Qué podemos hacer cuando nuestro programa debe elegir entre más de dos alternativas?, una posible solución podría ser emplear estructuras if anidadas, aunque no siempre esta solución es la más eficiente. Cuando estamos ante estas situaciones podemos utilizar la estructura de selección múltiple switch. En la siguiente tabla se muestra tanto la sintaxis, como el funcionamiento de esta estructura. Estructura switch Sintaxis: switch (expresion) { case valor1: sentencia1_1; sentencia1_2; …. break; …. …. case valorN: sentenciaN_1; sentenciaN_2; …. break; default: sentencias-default; } Condiciones: 9 Donde expresión debe ser del tipo char, byte, short o int, y las constantes de cada case deben ser de este tipo o de un tipo compatible. 9 La expresión debe ir entre paréntesis. 9 Cada case llevará asociado un valor y se finalizará con dos puntos. 9 El bloque de sentencias asociado a la cláusula default puede finalizar con una sentencia de ruptura break o no. Funcionamiento: 9 Las diferentes alternativas de esta estructura estarán precedidas de la cláusula case que se ejecutará cuando el valor asociado al case coincida con el valor obtenido al evaluar la expresión del switch. 9 En las cláusulas case, no pueden indicarse expresiones condicionales, rangos de valores o listas de valores. (otros lenguajes de programación sí lo permiten). Habrá que asociar una cláusula case a cada uno de los valores que deban ser tenidos en cuenta. 9 La cláusula default será utilizada para indicar un caso por defecto, las sentencias asociadas a la cláusula default se ejecutarán si ninguno de los valores indicados en las cláusulas case coincide con el resultado de la evaluación de la expresión de la estructura switch. 9 La cláusula default puede no existir, y por tanto, si ningún case ha sido activado finalizaría el switch. 9 Cada cláusula case puede llevar asociadas una o varias sentencias, sin necesidad de delimitar dichos bloques por medio de llaves. 9 En el momento en el que el resultado de la evaluación de la expresión coincide con alguno de los valores asociados a las cláusulas case, se ejecutarán todas las instrucciones asociadas hasta la aparición de una sentencia break de ruptura. (la sentencia break se analizará en epígrafes posteriores) ‐9‐ Uso de estructuras de control DAW En resumen, se ha de comparar el valor de una expresión con un conjunto de constantes, si el valor de la expresión coincide con algún valor de dichas constantes, se ejecutarán los bloques de instrucciones asociados a cada una de ellas. Si no existiese coincidencia, se ejecutarían una serie de instrucciones por defecto. DEBES CONOCER Comprueba el siguiente fragmento de código en el que se resuelve el cálculo de la nota de un examen de tipo test, utilizando la estructura switch. package sentencias_condicionales; /** * * @author Pc */ public class condicional_switch { /*Vamos a realizar el cálculo de la nota de un examen * de tipo test. Para ello, tendremos en cuenta el número * total de preguntas, los aciertos y los errores. Dos errores * anulan una respuesta correcta. * * La nota que vamos a obtener será un número entero. * * Finalmente, se muestra por pantalla la nota obtenida, así * como su calificación no numérica. * * La obtención de la calificación no numérica se ha realizado * utilizando la estructura condicional múltiple o switch. * */ public static void main(String[] args) { // Declaración e inicialización de variables int num_aciertos = 17; int num_errores = 3; int num_preguntas = 20; int nota = 0; String calificacion=""; //Procesamiento de datos nota = ((num_aciertos - (num_errores/2))*10)/num_preguntas; switch (nota) { case 5: calificacion="SUFICIENTE"; break; case 6: calificacion="BIEN"; break; case 7: calificacion="NOTABLE"; break; case 8: calificacion="NOTABLE"; break; case 9: calificacion="SOBRESALIENTE"; break; case 10: calificacion="SOBRESALIENTE"; break; default: calificacion="INSUFICIENTE"; } //Salida de información System.out.println ("La nota obtenida es: " + nota); System.out.println ("y la calificación obtenida es: " + calificacion); } } ‐ 10 ‐ Diseño de Aplicaciones Web Tema 4 4. Estructuras de repetición CASO PRÁCTICO Juan ya tiene claro cómo realizar la comprobación de los valores de login y contraseña introducidos por teclado, pero le surge una duda: ¿Cómo podría controlar el número de veces que el usuario ha introducido mal la contraseña? Ada le indica que podría utilizar una estructura de repetición que solicitase al usuario la introducción de la contraseña hasta un máximo de tres veces. Aunque comenta que puede haber múltiples soluciones y todas válidas, lo importante es conocer las herramientas que podemos emplear y saber cuándo aplicarlas. Nuestros programas ya son capaces de controlar su ejecución teniendo en cuenta determinadas condiciones, pero aún hemos de aprender un conjunto de estructuras que nos permita repetir una secuencia de instrucciones determinada. La función de estas estructuras es repetir la ejecución de una serie de instrucciones teniendo en cuenta una condición. A este tipo de estructuras se las denomina estructuras de repetición, estructuras repetitivas, bucles o estructuras iterativas. En Java existen cuatro clases de bucles: 9 9 9 9 Bucle for (repite para) Bucle for/in (repite para cada) Bucle While (repite mientras) Bucle Do While (repite hasta) Los bucles for y for/in se consideran bucles controlados por contador. Por el contrario, los bucles while y do...while se consideran bucles controlados por sucesos. La utilización de unos bucles u otros para solucionar un problema dependerá en gran medida de las siguientes preguntas: 9 ¿Sabemos a priori cuántas veces necesitamos repetir un conjunto de instrucciones? 9 ¿Sabemos si hemos de repetir un conjunto de instrucciones si una condición satisface un conjunto de valores? 9 ¿Sabemos hasta cuándo debemos estar repitiendo un conjunto de instrucciones? 9 ¿Sabemos si hemos de estar repitiendo un conjunto de instrucciones mientras se cumpla una condición? RECOMENDACIÓN Estudia cada tipo de estructura repetitiva, conoce su funcionamiento y podrás llegar a la conclusión de que algunos de estos bucles son equivalentes entre sí. Un mismo problema, podrá ser resuelto empleando diferentes tipos de bucles y obtener los mismos resultados. Estas y otras preguntas tendrán su respuesta en cuanto analicemos cada una de estructuras repetitivas en detalle. 4.1. Estructura for Hemos indicado anteriormente que el bucle for es un bucle controlado por contador. Este tipo de bucle tiene las siguientes características: 9 Se ejecuta un número determinado de veces. ‐ 11 ‐ Uso de estructuras de control DAW 9 Utiliza una variable contadora que controla las iteraciones del bucle. En general, existen tres operaciones que se llevan a cabo en este tipo de bucles: 9 Se inicializa la variable contadora. 9 Se evalúa el valor de la variable contador, por medio de una comparación de su valor con el número de iteraciones especificado. 9 Se modifica o actualiza el valor del contador a través de incrementos o decrementos de éste, en cada una de las iteraciones. RECOMENDACIÓN La inicialización de la variable contadora debe realizase correctamente para garantizar que el bucle lleve a cabo, al menos, la primera repetición de su código interno. La condición de terminación del bucle debe variar en el interior del mismo, de no ser así, podemos caer en la creación de un bucle infinito. Cuestión que se debe evitar por todos los medios. Es necesario estudiar el número de veces que se repite el bucle, pues debe ajustarse al número de veces estipulado. En la siguiente tabla, podemos ver la especificación de la estructura for: Estructura repetitiva for 9 Donde inicialización es una Sintaxis: expresión en la que se inicializa una variable for (inicialización; condición; iteración) de control, que será la encargada de sentencia; controlar el final del bucle. (estructura for con una única sentencia) 9 Donde condición es una expresión que evaluará la variable de control. Mientras la Sintaxis: condición sea falsa, el cuerpo del bucle for (inicialización; condición; iteración) estará repitiéndose. Cuando la condición se { cumpla, terminará la ejecución del bucle. sentencia1; sentencia2; 9 Donde iteración indica la manera en la ... que la variable de control va cambiando en sentenciaN; } cada iteración del bucle. Podrá ser mediante (estructura for con un bloque de sentencias) incremento o decremento, y no solo de uno en uno. DEBES CONOCER Como venimos haciendo para el resto de estructuras, observa el siguiente archivo Java y podrás analizar un ejemplo de utilización del bucle for para la impresión por pantalla de la tabla de multiplicar del siete. Lee atentamente los comentarios incluidos en el código, pues aclaran algunas cuestiones interesantes sobre este bucle. public class repetitiva_for { /* En este ejemplo se utiliza la estructura repetitiva for * para representar en pantalla la tabla de multiplicar del siete */ public static void main(String[] args) { // Declaración e inicialización de variables int numero = 7; int contador; int resultado=0; //Salida de información System.out.println ("Tabla de multiplicar del " + numero); System.out.println (".............................. "); ‐ 12 ‐ Diseño de Aplicaciones Web Tema 4 //Utilizamos ahora el bucle for for (contador=1; contador<=10;contador++) /* La cabecera del bucle incorpora la inicialización de la variable * de control, la condición de multiplicación hasta el 10 y el * incremento de dicha variable de uno en uno en cada iteración del * bucle. * En este caso contador++ incrementará en una unidad el valor de * dicha variable. */ { resultado = contador * numero; System.out.println(numero + " x " + contador + " = " + resultado); /* A través del operador + aplicado a cadenas de caracteres, * concatenamos los valores de las variables con las cadenas de * caracteres que necesitamos para representar correctamente la * salida de cada multiplicación. */ } } } AUTOEVALUACIÓN Cuando construimos la cabecera de un bucle for, podemos prescindir de alguno de los tres elementos que la forman e incluso, podemos utilizar más de una variable contadora separando éstas por comas. Pero, ¿Qué conseguiremos si construimos un bucle de la siguiente forma? for (;;){ //instrucciones } Un bucle infinito. Nada, dará un error. Un bucle que se ejecutaría una única vez. La construcción de la cabecera del bucle ha prescindido de cada una de las partes típicas (inicialización, condición e iteración), pero al mantener los puntos y comas en los lugares adecuados, el conjunto de instrucciones que pudieran incluirse en el cuerpo del bucle estarán ejecutándose eternamente. 4.2. Estructura for/in Junto a la estructura for, for/in también se considera un bucle controlado por contador. Este bucle es una mejora incorporada en la versión 5.0. de Java. Este tipo de bucles permite realizar recorridos sobre arrays y colecciones de objetos. Los arrays son colecciones de variables que tienen el mismo tipo y se referencian por un nombre común. Así mismo, las colecciones de objetos son objetos que se dice son iterables, o que se puede iterar sobre ellos. Este bucle es nombrado también como bucle for mejorado, o bucle foreach. En otros lenguajes de programación existen bucles muy parecidos a este. La sintaxis es la siguiente: ‐ 13 ‐ Uso de estructuras de control DAW for (declaración: expresión) { sentencia1; … sentenciaN; } 9 Donde expresión es un array o una colección de objetos. 9 Donde declaración es la declaración de una variable cuyo tipo sea compatible con expresión. Normalmente, será el tipo y el nombre de la variable a declarar. El funcionamiento consiste en que para cada elemento de la expresión, guarda el elemento en la variable declarada y haz las instrucciones contenidas en el bucle. Después, en cada una de las iteraciones del bucle tendremos en la variable declarada el elemento actual de la expresión. Por tanto, para el caso de los arrays y de las colecciones de objetos, se recorrerá desde el primer elemento que los forma hasta el último. Observa el contenido del código representado en la siguiente imagen, puedes apreciar cómo se construye un bucle de este tipo y su utilización sobre un array. Los bucles for/in permitirán al programador despreocuparse del número de veces que se ha de iterar, pero no sabremos en qué iteración nos encontramos salvo que se añada artificialmente alguna variable contadora que nos pueda ofrecer esta información. 4.3. Estructura while El bucle while es la primera de las estructuras de repetición controladas por sucesos que vamos a estudiar. La utilización de este bucle responde al planteamiento de la siguiente pregunta: ¿Qué podemos hacer si lo único que sabemos es que se han de repetir un conjunto de instrucciones mientras se cumpla una determinada condición?. La característica fundamental de este tipo de estructura repetitiva estriba en ser útil en aquellos casos en los que las instrucciones que forman el cuerpo del bucle podría ser necesario ejecutarlas o no. Es decir, en el bucle while siempre se evaluará la condición que lo controla, y si dicha condición es cierta, el cuerpo del bucle se ejecutará una vez, y se seguirá ejecutando mientras la condición sea cierta. Pero si en la evaluación inicial de la condición ésta no es verdadera, el cuerpo del bucle no se ejecutará. Es imprescindible que en el interior del bucle while se realice alguna acción que modifique la condición que controla la ejecución del mismo, en caso contrario estaríamos ante un bucle infinito. Estructura repetitiva while Sintaxis: Sintaxis: while (condición) sentencia; while (condición) { sentencia1; … sentenciaN; } Funcionamiento: Mientras la condición sea cierta, el bucle se repetirá, ejecutando la/s instrucción/es de su interior. En el momento en el que la condición no se cumpla, el control del flujo del programa pasará a la siguiente instrucción que exista justo detrás del bucle while. La condición se evaluará siempre al principio, y podrá darse el caso de que las instrucciones contenidas en él no lleguen a ejecutarse nunca si no se satisface la condición de partida. ‐ 14 ‐ Diseño de Aplicaciones Web Tema 4 En la siguiente imagen puedes ver un diagrama de flujo que representa el funcionamiento de este tipo de estructura DEBES CONOCER Observa el siguiente código java y podrás analizar un ejemplo de utilización del bucle while para la impresión por pantalla de la tabla de multiplicar del siete. Lee atentamente los comentarios incluidos en el código, pues aclaran algunas cuestiones interesantes sobre este bucle. Como podrás comprobar, el resultado de este bucle es totalmente equivalente al obtenido utilizando el bucle for. public class repetitiva_while { public static void main(String[] args) { // Declaración e inicialización de variables int numero = 7; int contador; int resultado=0; //Salida de información System.out.println ("Tabla de multiplicar del " + numero); System.out.println (".............................. "); //Utilizamos ahora el bucle while contador = 1; //inicializamos la variable contadora while (contador <= 10) //Establecemos la condición del bucle { resultado = contador * numero; System.out.println(numero + " x " + contador + " = " + resultado); //Modificamos el valor de la variable contadora, para hacer que el //bucle pueda seguir iterando hasta llegar a finalizar contador++; } } } AUTOEVALUACIÓN Utilizando el siguiente fragmento de código estamos construyendo un bucle infinito. while (true) System.out.println(“Imprimiendo desde dentro del bucle \n”); Verdadero Falso La condición del bucle siempre será cierta y estará continuamente ejecutándose. 4.4. Estructura do­while La segunda de las estructuras repetitivas controladas por sucesos es do­while. En este caso, la pregunta que nos planteamos es la siguiente: ¿Qué podemos hacer si lo único que sabemos es que se han de ejecutar, al menos una vez, un conjunto de instrucciones y seguir repitiéndose hasta que se cumpla una determinada condición?. La característica fundamental de este tipo de estructura repetitiva estriba en ser útil en aquellos casos en los que las instrucciones que forman el cuerpo del bucle necesitan ser ejecutadas, al menos, una vez y repetir su ejecución hasta que la condición sea verdadera. Por tanto, en esta estructura repetitiva siempre se ejecuta el cuerpo del bucle una primera vez. Es imprescindible que en el interior del bucle se realice alguna acción que modifique la condición que controla la ejecución del mismo, en caso contrario estaríamos ante un bucle infinito. ‐ 15 ‐ Uso de estructuras de control DAW Estructura repetitiva do‐while Sintaxis: do { Sintaxis: do sentencia; while (condición); sentencia1; … sentenciaN; } while (condición); Funcionamiento: El cuerpo del bucle se ejecuta la primera vez, a continuación se evaluará la condición y, si ésta es falsa, el cuerpo el bucle volverá a repetirse. El bucle finalizará cuando la evaluación de la condición sea verdadera. En ese momento el control del flujo del programa pasará a la siguiente instrucción que exista justo detrás del bucle do‐while. La condición se evaluará siempre después de una primera ejecución del cuerpo del bucle, por lo que no se dará el caso de que las instrucciones contenidas en él no lleguen a ejecutarse nunca. En la siguiente imagen puedes ver un diagrama de flujo que representa el funcionamiento de este tipo de estructura repetitiva. DEBES CONOCER Accede al siguiente archivo java y podrás analizar un ejemplo de utilización del bucle do­while para la impresión por pantalla de la tabla de multiplicar del siete. Lee atentamente los comentarios incluidos en el código, pues aclaran algunas cuestiones interesantes sobre este bucle. Como podrás comprobar, el resultado de este bucle es totalmente equivalente al obtenido utilizando el bucle for y el bucle while. public class repetitiva_dowhile { public static void main(String[] args) { // Declaración e inicialización de variables int numero = 7; int contador; int resultado=0; //Salida de información System.out.println ("Tabla de multiplicar del " + numero); System.out.println (".............................. "); //Utilizamos ahora el bucle do-while contador = 1; //inicializamos la variable contadora do { resultado = contador * numero; System.out.println(numero + " x " + contador + " = " + resultado); //Modificamos el valor de la variable contadora, para hacer que el //bucle pueda seguir iterando hasta llegar a finalizar contador++; }while (contador <= 10); //Establecemos la condición del bucle } } ‐ 16 ‐ Diseño de Aplicaciones Web Tema 4 5. Estructuras de salto CASO PRÁCTICO Juan recuerda que algunos lenguajes de programación permitían realizar saltos a lo largo de la ejecución de los programas y conoce dos sentencias que aún se siguen utilizando para ello. Ada, mientras toma un libro sobre Java de la estantería del despacho, le aconseja: –Las instrucciones de salto a veces han sido mal valoradas por la comunidad de programadores, pero en Java algunas de ellas son totalmente necesarias. Mira, en este libro se habla del uso de las sentencias break, continue y return... – ¿Saltar o no saltar? he ahí la cuestión. En la gran mayoría de libros de programación y publicaciones de Internet, siempre se nos recomienda que prescindamos de sentencias de salto incondicional, es más, se desaconseja su uso por provocar una mala estructuración del código y un incremento en la dificultad para el mantenimiento de los mismos. Pero Java incorpora ciertas sentencias o estructuras de salto que es necesario conocer y que pueden sernos útiles en algunas partes de nuestros programas. Estas estructuras de salto corresponden a las sentencias break, continue, las etiquetas de salto y la sentencia return. Pasamos ahora a analizar su sintaxis y funcionamiento. 5.1. Sentencias break y continue Se trata de dos instrucciones que permiten modificar el comportamiento de otras estructuras o sentencias de control, simplemente por el hecho de estar incluidas en algún punto de su secuencia de instrucciones. La sentencia break incidirá sobre las estructuras de control switch, while, for y do­while del siguiente modo: 9 Si aparece una sentencia break dentro de la secuencia de instrucciones de cualquiera de las estructuras mencionadas anteriormente, dicha estructura terminará inmediatamente. 9 Si aparece una sentencia break dentro de un bucle anidado sólo finalizará la sentencia de iteración más interna, el resto se ejecuta de forma normal. Es decir, que break sirve para romper el flujo de control de un bucle, aunque no se haya cumplido la condición del bucle. Si colocamos un break dentro del código de un bucle, cuando se alcance el break, automáticamente se saldrá del bucle pasando a ejecutarse la siguiente instrucción inmediatamente después de él. En la siguiente imagen, puedes apreciar cómo se utilizaría la sentencia break dentro de un bucle for. La sentencia continue incidirá sobre las sentencias o estructuras de control while, for y do‐while del siguiente modo: 9 Si aparece una sentencia continue dentro de la secuencia de instrucciones de cualquiera de las sentencias anteriormente indicadas, dicha sentencia dará por terminada la iteración actual y se ejecuta una nueva iteración, evaluando de nuevo la expresión condicional del bucle. ‐ 17 ‐ Uso de estructuras de control DAW 9 Si aparece en el interior de un bucle anidado solo afectará a la sentencia de iteración más interna, el resto se ejecutaría de forma normal. Es decir, la sentencia continue forzará a que se ejecute la siguiente iteración del bucle, sin tener en cuenta las instrucciones que pudiera haber después del continue, y hasta el final del código del bucle. En la imagen de la izquierda, puedes apreciar cómo se utiliza la sentencia continue en un bucle for para imprimir por pantalla sólo los números pares. Para clarificar algo más el funcionamiento de ambas sentencias de salto, te ofrecemos a la derecha un diagrama representativo. AUTOEVALUACIÓN La instrucción break puede utilizarse en las estructuras de control switch, while, for y dowhile, no siendo imprescindible utilizarla en la cláusula default de la estructura switch. Verdadero Falso si en una cláusula default no existe una sentencia break, directamente se pasaría a la finalización de la estructura condicional múltiple. 5.2. Etiquetas Ya lo indicábamos al comienzo del epígrafe dedicado a las estructuras de salto, los saltos incondicionales y en especial, saltos a una etiqueta son totalmente desaconsejables. No obstante, Java permite asociar etiquetas cuando se va a realizar un salto. De este modo puede conseguirse algo más de legibilidad en el código. Las estructuras de salto break y continue, pueden tener asociadas etiquetas. Es a lo que se llama un break etiquetado o un continue etiquetado. Pero sólo se recomienda su uso cuando se hace necesario salir de bucles anidados hacia diferentes niveles. ¿Y cómo se crea un salto a una etiqueta? En primer lugar, crearemos la etiqueta mediante un identificador seguido de dos puntos (:). A continuación, se escriben las sentencias Java asociadas a dicha etiqueta encerradas entre llaves. Por así decirlo, la creación de una etiqueta es como fijar un punto de salto en el programa para poder saltar a él desde otro lugar de dicho programa. ‐ 18 ‐ Diseño de Aplicaciones Web Tema 4 ¿Cómo se lleva a cabo el salto? Es sencillo, en el lugar donde vayamos a colocar la sentencia break o continue, añadiremos detrás el identificador de la etiqueta. Con ello, conseguiremos que el salto se realice a un lugar determinado. La sintaxis será break <etiqueta>. Quizá a aquellos/as que han programado en HTML les suene esta herramienta, ya que tiene cierta similitud con las anclas que pueden crearse en el interior de una página web, a las que nos llevará el hiperenlace o link que hayamos asociado. También para aquellos/as que han creado alguna vez archivos por lotes o archivos batch bajo MSDOS es probable que también les resulte familiar el uso de etiquetas, pues la sentencia GOTO que se utilizaba en este tipo de archivos, hacía saltar el flujo del programa al lugar donde se ubicaba la etiqueta que se indicara en dicha sentencia. A continuación, te ofrecemos un ejemplo de declaración y uso de etiquetas en un bucle. Como podrás apreciar, las sentencias asociadas a cada etiqueta están encerradas entre llaves para delimitar así su ámbito de acción. 5.3. Sentencia Return Ya sabemos cómo modificar la ejecución de bucles y estructuras condicionales múltiples, pero ¿Podríamos modificar la ejecución de un método? ¿Es posible hacer que éstos detengan su ejecución antes de que finalice el código asociado a ellos?. Sí es posible, a través de la sentencia return podremos conseguirlo. La sentencia return puede utilizarse de dos formas: 9 Para terminar la ejecución del método donde esté escrita, con lo que transferirá el control al punto desde el que se hizo la llamada al método, continuando el programa por la sentencia inmediatamente posterior. 9 Para devolver o retornar un valor, siempre que junto a return se incluya una expresión de un tipo determinado. Por tanto, en el lugar donde se invocó al método se obtendrá el valor resultante de la evaluación de la expresión que acompañaba al método. En general, una sentencia return suele aparecer al final de un método, de este modo el método tendrá una entrada y una salida. También es posible utilizar una sentencia return en cualquier punto de un método, con lo que éste finalizará en el lugar donde se encuentre dicho return. No será recomendable incluir más de un return en un método y por regla general, deberá ir al final del método como hemos comentado. El valor de retorno es opcional, si lo hubiera debería de ser del mismo tipo o de un tipo compatible al tipo del valor de retorno definido en la cabecera del método, pudiendo ser desde un entero a un objeto creado por nosotros. Si no lo tuviera, el tipo de retorno sería void, y return serviría para salir ‐ 19 ‐ Uso de estructuras de control DAW del método sin necesidad de llegar a ejecutar todas las instrucciones que se encuentran después del return. PARA SABER MÁS En el siguiente archivo java encontrarás el código de un programa que obtiene la suma de dos números, empleando para ello un método sencillo que retorna el valor de la suma de los números que se le han pasado como parámetros. Presta atención a los comentarios y fíjate en las conversiones a entero de la entrada de los operandos por consola. import java.io.*; /** * * Uso de return en un método */ public class sentencia_return { private static BufferedReader InputStreamReader(System.in)); stdin = new BufferedReader( new public static int suma(int numero1, int numero2) { int resultado; resultado = numero1 + numero2; return resultado; //Mediante return devolvemos el resultado de la suma } public static void main(String[] args) throws IOException { //Declaración de variables String input; //Esta variable recibirá la entrada de teclado int primer_numero, segundo_numero; //Estas variables almacenarán los operandos // Solicitamos que el usuario introduzca dos números por consola System.out.print ("Introduce el primer operando:"); input = stdin.readLine(); //Leemos la entrada como cadena de caracteres primer_numero = Integer.parseInt(input); //Transformamos a entero lo introducido System.out.print ("Introduce el segundo operando: "); input = stdin.readLine(); //Leemos la entrada como cadena de caracteres segundo_numero = Integer.parseInt(input); //Transformamos a entero lo introducido //Imprimimos los números introducidos System.out.println ("Los operandos son: " + primer_numero + " y " + segundo_numero); System.out.println ("obteniendo su suma... "); //Invocamos al método que realiza la suma, pasándole los parámetros adecuados System.out.println ("La suma de ambos operandos es: suma(primer_numero,segundo_numero)); " + } } AUTOEVALUACIÓN ¿Qué afirmación es correcta? Con return, se puede finalizar la ejecución del método en el que se encuentre. Con return, siempre se retornará un valor del mismo tipo o de un tipo compatible al definido en la cabecera del método. Con return, puede retornarse un valor de un determinado tipo y suele hacerse al final del método. Además, el resto de respuestas también son correctas. Efectivamente, si encontramos un return antes de la finalización del código asociado a un método, éste devolverá el control del flujo del programa a la instrucción inmediatamente posterior que existiese tras la invocación al método. ‐ 20 ‐ Diseño de Aplicaciones Web Tema 4 6. Excepciones CASO PRÁCTICO Para que las aplicaciones desarrolladas por BK Programación mantengan una valoración positiva a lo largo del tiempo por parte de sus clientes, es necesario que éstas no se vean comprometidas durante su ejecución. Hay innumerables ocasiones en las que programas que aparentemente son formidables (por su interfaz, facilidad de uso, etc.) comienzan a generar errores en tiempo de ejecución que hacen que el usuario desconfíe de ellos día a día. Para evitar estas situaciones, Ada va a fomentar en María y Juan la cultura de la detección, control y solución de errores a través de las poderosas herramientas que Java les ofrece. A lo largo de nuestro aprendizaje de Java nos hemos topado en alguna ocasión con errores, pero éstos suelen ser los que nos ha indicado el compilador. Un punto y coma por aquí, un nombre de variable incorrecto por allá, pueden hacer que nuestro compilador nos avise de estos descuidos. Cuando los vemos, se corrigen y obtenemos nuestra clase compilada correctamente. Pero, ¿Sólo existen este tipo de errores? ¿Podrían existir errores no sintácticos en nuestros programas?. Está claro que sí, un programa perfectamente compilado en el que no existen errores de sintaxis, puede generar otros tipos de errores que quizá aparezcan en tiempo de ejecución. A estos errores se les conoce como excepciones. Aprenderemos a gestionar de manera adecuada estas excepciones y tendremos la oportunidad de utilizar el potente sistema de manejo de errores que Java incorpora. La potencia de este sistema de manejo de errores radica en: 1. Que el código que se encarga de manejar los errores, es perfectamente identificable en los programas. Este código puede estar separado del código que maneja la aplicación. 2. Que Java tiene una gran cantidad de errores estándar asociados a multitud de fallos comunes, como por ejemplo divisiones por cero, fallos de entrada de datos, etc. Al tener tantas excepciones localizadas, podemos gestionar de manera específica cada uno de los errores que se produzcan. En Java se pueden preparar los fragmentos de código que pueden provocar errores de ejecución para que si se produce una excepción, el flujo del programa es lanzado (throw) hacia ciertas zonas o rutinas que han sido creadas previamente por el programador y cuya finalidad será el tratamiento efectivo de dichas excepciones. Si no se captura la excepción, el programa se detendrá con toda probabilidad. En Java, las excepciones están representadas por clases. El paquete java.lang.Exception y sus subpaquetes contienen todos los tipos de excepciones. Todas las excepciones derivarán de la clase Throwable, existiendo clases más específicas. Por debajo de la clase Throwable existen las clases Error y Exception. Error es una clase que se encargará de los errores que se produzcan en la máquina virtual, no en nuestros programas. Y la clase Exception será la que a nosotros nos interese conocer, pues gestiona los errores provocados en los programas. Java lanzará una excepción en respuesta a una situación poco usual. Cuando se produce un error se genera un objeto asociado a esa excepción. Este objeto es de la clase Exception o de alguna de sus herederas. Este objeto se pasa al código que se ha definido para manejar la excepción. Dicho código puede manipular las propiedades del objeto Exception. ‐ 21 ‐ Uso de estructuras de control DAW El programador también puede lanzar sus propias excepciones. Las excepciones en Java serán objetos de clases derivadas de la clase base Exception. Existe toda una jerarquía de clases derivada de la clase base Exception. Estas clases derivadas se ubican en dos grupos principales: 9 Las excepciones en tiempo de ejecución, que ocurren cuando el programador no ha tenido cuidado al escribir su código. 9 Las excepciones que indican que ha sucedido algo inesperado o fuera de control. En la siguiente imagen te ofrecemos una aproximación a la jerarquía de las excepciones en Java. 6.1. Capturar una excepción Para poder capturar excepciones, emplearemos la estructura de captura de excepciones try‐catch‐ finally. Básicamente, para capturar una excepción lo que haremos será declarar bloques de código donde es posible que ocurra una excepción. Esto lo haremos mediante un bloque try (intentar). Si ocurre una excepción dentro de estos bloques, se lanza una excepción. Estas excepciones lanzadas se pueden capturar por medio de bloques catch. Será dentro de este tipo de bloques donde se hará el manejo de las excepciones. Su sintaxis es: try { código que puede generar excepciones; } catch (Tipo_excepcion_1 objeto_excepcion) { Manejo de excepción de Tipo_excepcion_1; } catch (Tipo_excepcion_2 objeto_excepcion) { Manejo de excepción de Tipo_excepcion_2; } ... finally { instrucciones que se ejecutan siempre } En esta estructura, la parte catch puede repetirse tantas veces como excepciones diferentes se deseen capturar. La parte finally es opcional y, si aparece, solo podrá hacerlo una sola vez. Cada catch maneja un tipo de excepción. Cuando se produce una excepción, se busca el catch que posea el manejador de excepción adecuado, será el que utilice el mismo tipo de excepción que se ha producido. Esto puede causar problemas si no se tiene cuidado, ya que la clase Exception es la ‐ 22 ‐ Diseño de Aplicaciones Web Tema 4 superclase de todas las demás. Por lo que si se produjo, por ejemplo, una excepción de tipo AritmethicException y el primer catch captura el tipo genérico Exception, será ese catch el que se ejecute y no los demás. Por eso el último catch debe ser el que capture excepciones genéricas y los primeros deben ser los más específicos. Lógicamente si vamos a tratar a todas las excepciones (sean del tipo que sean) igual, entonces basta con un solo catch que capture objetos Exception. EJERCICIO RESUELTO Realiza un programa en Java en el que se solicite al usuario la introducción de un número por teclado comprendido entre el 0 y el 100. Utilizando manejo de excepciones, debes controlar la entrada de dicho número y volver a solicitarlo en caso de que ésta sea incorrecta. /* * Ejercicio resuelto sobre manejo de excepciones. * El programa solicita que el usuario introduzca por teclado * un número entre 0 y 100, debiendo gestionarse la entrada * por medio de excepciones. */ import java.io.*; public class ejercicio_resuelto_excepciones { public static void main(String[] args){ int numero=-1; int intentos=0; String linea; BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in)); do{ try{ System.out.print("Introduzca un número entre 0 y 100: "); linea = teclado.readLine(); numero = Integer.parseInt(linea); }catch(IOException e){ System.out.println("Error al leer del teclado."); }catch(NumberFormatException e){ System.out.println("Debe introducir un número entre 0 y 100."); }finally{ intentos++; } }while (numero < 0 || numero > 100); System.out.println("El número introducido es: " + numero); System.out.println("Número de intentos: " + intentos); } } En este programa se solicita repetidamente un número utilizando una estructura do­while, mientras el número introducido sea menor que 0 y mayor que 100. Como al solicitar el número pueden producirse los errores siguientes: 9 De entrada de información a través de la excepción IOException generada por el método readLine() de la clase BufferedReader. 9 De conversión de tipos a través de la excepción NumberFormatException generada por el método parseInt(). Entonces se hace necesaria la utilización de bloques catch que gestionen cada una de las excepciones que puedan producirse. Cuando se produce una excepción, se compara si coincide con la excepción del primer catch. Si no coincide, se compara con la del segundo catch y así sucesivamente. Si se ‐ 23 ‐ Uso de estructuras de control DAW encuentra un catch que coincide con la excepción a gestionar, se ejecutará el bloque de sentencias asociado a éste. Si ningún bloque catch coincide con la excepción lanzada, dicha excepción se lanzará fuera de la estructura try‐catch‐finally. El bloque finally, se ejecutará tanto si try terminó correctamente, como si se capturó una excepción en algún bloque catch. Por tanto, si existe bloque finally éste se ejecutará siempre. DEBES CONOCER Si deseas conocer en mayor detalle el manejo de excepciones, te aconsejamos el siguiente enlace en el que podrás encontrar un vídeo ilustrativo sobre su creación y manejo. http://www.youtube.com/watch?v=2gWTVxe31g8&feature=related El video comienza indicando que existen varias formas de capturar las posibles excepciones que nuestros programas pueden generar. La estructura try‐catch es analizada en primer lugar, a través de un ejemplo que convierte una cadena de texto a entero. Primero se hace una gestión de la excepción de manera sencilla y, posteriormente, se van añadiendo bloques catch para incluir diferentes posibilidades de tratamiento de la excepción en función del error generado. Seguidamente, se hace referencia a la utilización de la sentencia throw exception para indicar que un método puede generar una excepción, pero ésta no será gestionada por el propio método, sino por el que lo llamó. Es a lo que se llama propagación de excepciones. AUTOEVALUACIÓN Si en un programa no capturamos una excepción, será la máquina virtual de Java la que lo hará por nosotros, pero inmediatamente detendrá la ejecución del programa y mostrará una traza y un mensaje de error. Siendo una traza, la forma de localizar dónde se han producido errores. Verdadero Falso Así es, si un método no gestiona las excepciones que se producen en él, la excepción será pasada al método que llamó al método. Y así ocurrirá sucesivamente si no existe gestión de las excepciones en niveles superiores, hasta llegar a la máquina virtual de Java que detendrá la ejecución del programa. 6.2. El manejo de excepciones Como hemos comentado, siempre debemos controlar las excepciones que se puedan producir o de lo contrario nuestro software quedará expuesto a fallos. Las excepciones pueden tratarse de dos formas: 9 Interrupción. En este caso se asume que el programa ha encontrado un error irrecuperable. La operación que dio lugar a la excepción se anula y se entiende que no hay manera de regresar al código que provocó la excepción. Es decir, la operación que dio originó el error, se anula. 9 Reanudación. Se puede manejar el error y regresar de nuevo al código que provocó el error. Java emplea la primera forma, pero puede simularse la segunda mediante la utilización de un bloque try en el interior de un while, que se repetirá hasta que el error deje de existir. En la siguiente imagen tienes un ejemplo de cómo llevar a cabo esta simulación. En este ejemplo, a través de la ‐ 24 ‐ Diseño de Aplicaciones Web Tema 4 función de generación de números aleatorios se obtiene el valor del índice i. Con dicho valor se accede a una posición del array que contiene cinco cadenas de caracteres. Este acceso, a veces puede generar un error del tipo ArrayIndexOutOfBoundsException, que debemos gestionar a través de un catch. Al estar el bloque catch dentro de un while, se seguirá intentando el acceso hasta que no haya error. 6.3. Delegación de excepciones con throws ¿Puede haber problemas con las excepciones al usar llamadas a métodos en nuestros programas? Efectivamente, si se produjese una excepción es necesario saber quién será el encargado de solucionarla. Puede ser que sea el propio método llamado o el código que hizo la llamada a dicho método. Quizá pudiéramos pensar que debería ser el propio método el que se encargue de sus excepciones, aunque es posible hacer que la excepción sea resuelta por el código que hizo la llamada. Cuando un método utiliza una sentencia que puede generar una excepción, pero dicha excepción no es capturada y tratada por él, sino que se encarga su gestión a quién llamó al método, decimos que se ha producido delegación de excepciones. Para establecer esta delegación, en la cabecera del método se declara el tipo de excepciones que puede generar y que deberán ser gestionadas por quien invoque a dicho método. Utilizaremos para ello la sentencia throws y tras esa palabra se indica qué excepciones puede provocar el código del método. Si ocurre una excepción en el método, el código abandona ese método y regresa al código desde el que se llamó al método. Allí se posará en el catch apropiado para esa excepción. Su sintaxis es la siguiente: public ... public String Return } ... } class delegacion_excepciones { int leeaño(BufferedReader lector) throws IOException, NumberFormatException{ linea = teclado.readLine(); Integer.parseInt(linea); Donde IOException y NumberFormatException, serían dos posibles excepciones que el método leeaño podría generar, pero que no gestiona. Por tanto, un método puede incluir en su cabecera un listado de excepciones que puede lanzar, separadas por comas. PARA SABER MÁS Si deseas saber algo más sobre la delegación de excepciones, te proponemos el siguiente enlace: http://dis.um.es/~bmoros/Tutorial/parte9/cap9‐3.html Además te volvemos a remitir al video demostrativo sobre manejo de excepciones en Java que se incluyó en el epígrafe anterior, titulado “capturar una excepción”. ‐ 25 ‐ Uso de estructuras de control DAW 7. Prueba de programas CASO PRÁCTICO Continuando con el especial interés de BK Programación porque sus aplicaciones sean de verdadera calidad, Ada está dispuesta a emprender un plan de pruebas de software que sea capaz de reducir al mínimo posible los errores que puedan contener las aplicaciones que están desarrollando. Juan y María ya conocían de la existencia de ciertas pruebas que se suelen hacer al software, pero necesitarán aprender bien las técnicas y utilizar las herramientas que los entornos de desarrollo ofrecen para tal proceso. A veces, los programas son complejos y es difícil hacer que éstos funcionen correctamente. Las pruebas del software son un conjunto de técnicas utilizadas para verificar que un programa lleva a cabo su tarea correctamente. Viéndolo desde otro punto de vista, podríamos decir que la realización de pruebas en nuestros programas intentan revelar la existencia de errores. Cuando detectamos que existe un error, necesitamos localizarlo llevando a cabo técnicas de depuración de código, para luego acometer las modificaciones necesarias que eliminen dicho error. No obstante, las técnicas de prueba del software no garantizan que todos los errores vayan a salir a la luz y aún así, habrá programas de gran tamaño que sigan conteniendo errores ocultos en ellos. De todas maneras, la realización de pruebas de software está considerada como una etapa de gran importancia en el desarrollo de software. Casi la mitad del tiempo dedicado al desarrollo de un programa, se emplea en la realización de pruebas al mismo. En algunas organizaciones, la realización de pruebas se considera tan importante que existen equipos de desarrollo de software en los que hay tantos probadores de software como programadores. Los procesos de prueba y depuración requieren una considerable cantidad de tiempo y esfuerzo, haciéndose difícil tomar una decisión acertada entre continuar la prueba del programa o entregarlo en su estado actual al cliente. Un concepto muy importante con el que vamos a trabajar es el de verificación de programas. La verificación de programas es un proceso por el que se intenta corroborar que un programa hace lo que se espera de él. Se trata de confirmar que el programa cumple con sus especificaciones. En esta parte de la unidad nos centraremos en las técnicas de prueba sistemática de programas, verificación y análisis de deficiencias del software. Las técnicas que veremos son: 9 9 9 9 Pruebas de caja negra o test funcionales. Pruebas de caja blanca o test estructurales. Revisiones o recorridos. Análisis paso a paso del código con un depurador (debugger). Un pequeño programa que consiste sólo en una única clase, normalmente puede ser probado de una sola vez. En cambio, un programa de mayor tamaño que incluye más cantidad de clases, es posible que por su complejidad, deba ser probado por partes. En Java, el tamaño natural de cada una de esas partes será la clase y será conveniente probar nuestros programas clase por clase. Esto es llamado Pruebas de Unidad. Y cuando se realizan pruebas de funcionamiento reuniendo todas las partes del programa completo, las pruebas reciben el nombre de Pruebas de Integración o Pruebas de Sistema. ‐ 26 ‐ Diseño de Aplicaciones Web Tema 4 AUTOEVALUACIÓN En el proceso de [ verificación ] se trata de confirmar que el programa cumple con sus [ especificaciones]. 7.1. La especificación El punto de partida para cualquier prueba es la especificación. No podemos considerar una pérdida de tiempo el análisis claro de dicha información. En ocasiones, podría ser necesario volver a entrevistar a un cliente o al futuro usuario del programa. Para entender la importancia de este elemento, supongamos la siguiente especificación: 9 Es necesario escribir un programa que solicite la entrada al usuario de números a través de cajas de texto. El programa debe calcular y mostrar la suma de los números. A priori, esta especificación puede parecer simple y clara. Nada más lejos de la realidad, ya que existen lagunas como: 1. ¿Los números son enteros o coma flotante? 2. ¿Cuál es el rango y precisión de dichos números? 3. ¿Pueden incluirse números negativos? Si estas preguntas no son aclaradas antes de que el programador comience su trabajo, pueden producirse dificultades en el desarrollo del programa. Por tanto, será parte del proceso de programación el estudio de la especificación para descubrir cualesquiera omisiones o confusión y para conseguir una especificación totalmente clara. A continuación se muestra una versión mucho más clara de la especificación anterior: 9 Es necesario escribir un programa que solicite la entrada al usuario de una serie de números enteros a través de una caja de texto. Los enteros están en el rango 0 a 10000. El programa calcula y muestra la suma de los números. Como puedes apreciar, esta especificación es más precisa al establecer el rango permitido de entrada de valores, por ejemplo. Una vez valorada la importancia de una correcta especificación, el programador puede comenzar el proceso de pruebas del software a través de las herramientas que se detallarán en los siguientes epígrafes de la unidad. 7.2. Pruebas exhaustivas ¿He de probar todas las posibilidades?, es una pregunta que puede surgir cuando comenzamos a programar. Podríamos pensar en que la realización de una prueba requeriría probar nuestro software con todos los posibles valores de entrada. Este tipo de prueba se denomina prueba exhaustiva y significa que seleccionamos todos los posibles valores de entrada, así como todas sus posibles combinaciones y hacemos que nuestro programa opere con ellos. Pensemos un momento en el amplio rango de posibles valores que pueden tomar los números int de Java. ¿Te imaginas lo que puede suponer realizar una prueba de este tipo? ¡podríamos estar hablando de años!. ‐ 27 ‐ Uso de estructuras de control DAW En resumen, la pruebaa exhaustivaa (aunque sea s para un n programa pequeño) n no es factib ble. Es importante reconocer que q la prueb ba completaa de program mas no es posible, por lo que tendrremos que adoptar otras técnicas más adeecuadas. AUTOEV VALUACIÓ ÓN Durante unna prueba exhaustiva e h hemos de seeleccionar una u muestraa de los possibles valorres de entrada deel programaa y hacer que q éste tom me diferentes caminoss de ejecuciión para veer los resultados que se obtieenen. Verd dadero Falsso No se trata de probar p los difereentes caminos dee ejecución, se tra ata de probar co on todos los posib bles valores de en ntrada del progrrama, lo cual puede resu ultar extremadam mente tedioso. 7.3. Prueb bas de Ca aja Negra o Pruebass Funcion nales Descartadass las pruebaas exhaustivvas, una téccnica más aadecuada paara la realización de d nuestras pruebas es el empleo de d las Pruebas de Caja Negra. N E tipo de pruebas se basa Este b en utilizzar unos dato os de entrad da que puede en ser representativo os de todos los posibles datos de en ntrada. Con ellos, se pone en funccionamiento el programaa y se analizaa qué ocurre.. d Caja Negrra porque no se utiliza ningún cono ocimiento deel funcionam miento intern no del Se llaman de programa como c parte de la prueb ba, sólo se consideran c laas entradas y las salidass. El program ma se piensa como si fuera un na caja negraa que recibe datos de en ntrada y ofrece unas salid das determin nadas. mbre de Pruebas Funcio onales porque utiliza solaamente el co onocimiento o de la También reeciben el nom función del programa (n no cómo trab baja internam mente). e resultado previsto, p anttes de ejecuttar la pruebaa. Es a Inicialmentee, se anotan los datos dee prueba y el lo que se deenomina esp pecificación o planificació ón de la prue eba. Posterio ormente, se pone el proggrama en funcionaamiento, se introducen los l datos y se s examinan las salidas para p ver si eexisten difere encias entre el resultado previsto y el resu ultado obteniido. Los dato os de pruebaa deberán también comp probar n manejadass por el programa, de acuerdo a su especificación. Es decir, si las excepciones son tendremos que ponerr en aprieto os a nuestrro programaa a través de unos d datos de en ntrada determinad dos, para com mprobar si reeacciona correctamente a las especifficaciones qu ue deba cumplir. 7.4. Pru uebas de Caja Blan nca o Prue ebas Estru ucturales Este otro tipo de prruebas se baasa en el conocimiento del funcionam miento intern no del program ma, la estrucctura del mismo para se eleccionar lo os datos de p prueba. A lo largo de las pruebas de caja blanca cada declarración que forma f parte del program ma es ejecutada en algún mom mento. Por lo o que cada secuencia de instruccionees o camino por el que pueda fluir el proggrama es ejecutada en alguna ocasió ón durante dicha d pruebaa. Considerándose caminos nu ulos, sentenccias condicionales simplees o compuestas, bucles,, etc. La prueeba deberá incluir i cualquier caamino del prrograma quee pueda geneerar una exce epción. Este tipo dee pruebas esttá muy ligado al código fuente f del prrograma, de tal forma, que la person na que realiza las pruebas p debee escoger disstintos valores de entrad da para cheq quear cada uno de los po osibles ‐ 28 ‐ Diseño de Aplicaciones Web Tema 4 caminos de ejecución que existen en el programa y verificar que los resultados de cada uno de ellos son adecuados. AUTOEVALUACIÓN Si nos encontramos realizando pruebas y estamos examinando el funcionamiento de un bucle while, estaremos realizando Pruebas de Caja [ Blanca ]. 7.5. Otras pruebas Además de las típicas pruebas de Caja Blanca y Negra, existen otras técnicas de prueba que detallamos a continuación: a) Revisiones, inspecciones o recorridos: Esta técnica no hace uso del computador para intentar erradicar errores en el código. En un recorrido se estudia el listado del programa (junto con la especificación) para intentar hacer visibles los posibles errores. Es recomendable que quien lleve a cabo el recorrido no sea la misma persona que desarrolló el código a revisar. Si has programado alguna vez, quizá te suene esta situación: Llevas más de una hora buscando un error en el código de tu programa, ya que éste te está generando errores de compilación o ejecución. Miras, vuelves a mirar, revisas, repasas, cambias alguna variable o sentencia, ...‐¡Nada, no encuentro el fallo!. De pronto, un colega relee tu código mientras se toma un café y oyes detrás de ti una voz que dice:‐¡Anda, te falta un paréntesis ahí!. Sabiduría popular: “Cuatro ojos ven más que dos”. Para llevar a cabo este tipo de prueba necesitaremos la especificación del programa y el código fuente en papel. Las acciones que suelen realizarse son: inspeccionar la inicialización de variables, realización de llamadas a métodos correctas, definición adecuada de cabeceras de métodos, parámetros correctos, etc. Posteriormente, se ha de llevar a cabo una revisión de la lógica del programa simulando ejecutar los métodos como si nosotros mismos fuéramos el computador. Las pruebas de revisión o recorrido no comprueban el estilo del código, sino posibles deficiencias que pueden provocar errores. Está demostrado que los recorridos son una vía adecuada para encontrar errores. a) Análisis paso a paso: Existen algunos entornos de desarrollo para Java que incorporan depuración paso a paso del código. Esto permite al programador ejecutar una a una cada instrucción de su programa. De este modo, es posible ver qué camino de ejecución se está tomando, los valores de las distintas variables, etc. Este análisis paso a paso está estructurado y automatizado, permitiéndonos comprobar si el flujo del programa es el correcto, si los valores de las variables varían en función de la ejecución del programa, etc. Esta técnica suele confirmar o desmentir la existencia de un determinado fallo, aunque está más cerca de la depuración de programas que de la propia prueba de los mismos. ‐ 29 ‐ Uso de estructuras de control DAW 7.6. Realización de Pruebas Unitarias con JUnit Al comienzo de esta parte de la unidad dedicada a las pruebas y depuración de software, hablamos de un tipo de pruebas que se aplican a cada una de las clases que hayamos definido. Eran las Pruebas Unitarias. Es cierto que cualquier código que escribamos debería de ser probado antes de dar por finalizada la implementación de una clase, ya que si no, no estaríamos totalmente seguros de su correcto funcionamiento. Para verificar que el código no contiene errores de programación y que además realiza adecuadamente lo que nosotros esperábamos de él, es realizando una serie de test que lo corroboren. ¿Quién no ha ido escribiendo mensajes de salida de texto a lo largo de su código? Esta es una técnica muy utilizada para controlar el valor de ciertas variables y para la detección de posibles errores, lo que confirma que todos realizamos pruebas a nuestros programas de alguna u otra manera. Pero, ¿Existen formas más avanzadas, eficientes y seguras de probar el código?, Sí. Podemos utilizar para ello JUnit. A través de JUnit tendremos la posibilidad de realizar test a nuestras clases de forma sencilla, rápida y elegante, así como validar los resultados que nos ofrecen. ¿Y qué es JUnit? Es un conjunto de bibliotecas que se utilizan en programación para hacer Pruebas Unitarias a aplicaciones Java. El conjunto de clases (framework) incluidas en JUnit permite controlar la ejecución de las clases Java, de tal forma que podremos evaluar si el funcionamiento de cada uno de los métodos de la clase realiza su trabajo como debería. JUnit se emplea para indicar si la clase en cuestión ha pasado los test de prueba, en otro caso se devolverá una notificación de fallo en el método correspondiente. Actualmente, el entorno de desarrollo NetBeans cuanta con plug‐ins que permiten la generación automática de plantillas de pruebas de clases Java. ¿Por qué utilizar JUnit? A continuación te damos algunas razones de peso por la que este framework está muy extendido entre la comunidad de programadores Java: 9 A través de los test de JUnit se incrementa la calidad y velocidad de generación de código. 9 La escritura de test es sencilla. 9 Los test JUnit chequean sus propios resultados y proporcionan información de retorno al instante. 9 Los tests JUnit incrementan la estabilidad del software. 9 Los test JUnit se escriben en Java. 9 JUnit es gratuito. PARA SABER MÁS El IDE NetBeans 7.0. ya incorpora JUnit desde la instalación, por lo que podemos beneficiarnos de esta herramienta de testeo sólo con utilizarla desde el IDE. Si quieres conocer cómo realizar los primeros pasos con ella y ver ejemplos de utilización, te recomendamos veas lo siguiente: Test con JUnit El viernes dicte un taller en el que conversábamos sobre Tecnologías Java y luego desarrollamos una aplicación muy básica para demostrar cómo utilizar JUnit con NetBeans. ‐ 30 ‐ Diseñ ño de Aplicacciones Web Tema 4 Pasoss 1 Creear un proyecto Desktop con n NetBeans 2 Creear una clasee llamada Operaciones 3 Diseñados un fo ormulario y agrregramos com mponentes de d manera que qu uede similar a la figu ura: Códiggo de los bottones try { do ouble a = Do ouble.parseDo ouble(jTextF Field1.getTe ext()); do ouble b = Do ouble.parseDo ouble(jTextF Field2.getTe ext()); Op peraciones operaciones o = new Operac ciones(); do ouble r = op peraciones.Su umar(a, b); jT TextField3.setText(Strin ng.valueOf(r r)); } cat tch (Excepti ion ex) { JO OptionPane.showMessageDialog(this, ex.getMessa age().toStri ing()); } 4 Creamos los test 5 S Seleccionam mos las clasess 6 En el menú Herramientaas, mos Crear pru uebas JUnit seleccionam 7 S Seleccionam mos la versión n de JUnit ‐ 31 ‐ Uso de estructuras de control 8 onamos En la ventana siguiente seleccio los parrámetros parra nuestras pruebas p . Le quittamos la seleección a Prob bar Inicializador y Prob bar Finalizado or 9 NetBeaans crea las clases c de Tesst. Observve que las claases terminaan en TEST os la clase OperacionesTTest.java. Abrimo 10 Se generar los méttodos de la clase originaal. Editam mos todas lass clases y comen ntamos la lineea fail("The test t case is a pro ototype."); colocando // 11 (comentarios) delaante de la sen ntencia. Ahora indicamos lo os parámetro os para el test y el e resultado. 12 Ejecutaamos el test Nos muestra la saliida color verrde 13 indican ndo que las pruebas p fuerron exitosaas. Pensem mos que algu uien por erro or cambia el código del método Sumar() quedando de esta manera 14 public double Suma ar(double a, , double b){ return a + b * 2; } Ejecutaamos nuevam mente el tesst ‐ 32 ‐ DAW Diseñ ño de Aplicacciones Web Tema 4 Observamoss en detalle la salida Esto indica en el método que e esta el erro or y podamo os corregirlo.. Era un tallee muy básico o para estud diantes que nunca han utilizado u Testt. mos otro paso o a paso de cómo c usar JU Unit en NetB Beans. Veam Crearr una clase (V Veamos cóm mo crear unaa clase de tesst) 1 SSobre la clase que deseamos t testear pulsaa con el botó ón d derecho en el e menú “ “Tools→Cre eate JUnit Test”. T 2 Pulsa “OK”. P Y se creará una u nueva claase de t con el essqueleto quee test p permitirá pro obar la clase. L nueva classe se crea en La n el m mismo paquete que la clase a t testear pero en la localización “ “Test Packagges”. Ademáss se llama c como la clasee original pero a añadiendo el sufijo Test. ‐ 33 ‐ Uso de estructuras de control 3 DAW Ahora ya puedes programar la clase de Test. Ejecutando los Test 1 2 Pulsa con el botón derecho sobre el proyecto y ejecuta la opción de menú “Test”. En este ejemplo podemos ver la siguiente información: Aparecerá en la ventana inferior a) % de test pasados (58,3%) , es decir lo que han funcionado. el resultado de ejecutar los Tests. b) El Nº de test pasados (7 tests) , el Nº de test que han fallado (5 Tests) y el tiempo que han tardado en ejecutarse (0,266 segundos) c) El icono en verde significa que todos los test de esa clase han funcionado correctamente. d) El icono en rojo significa que al menos un test ha fallado. e) El icono en verde significa que ese test concreto en la clase ha funcionado correctamente. ‐ 34 ‐ Diseño de Aplicaciones Web Tema 4 f) Los iconos amarillo significan que son Test que han fallado. Mira ahora el siguiente vídeo de ejemplos con JUnit http://www.youtube.com/watch?v=Sk‐QH637rpM En este video se realiza una introducción inicial a las funciones principales del framework JUnit, posteriormente se indica dónde y cómo llevar a cabo la descarga del framework y su instalación como plug‐in en el IDE Eclipse. (Estas acciones no habría que llevarlas a cabo en NetBeans 7.0.). A continuación, a través de un ejemplo de suma de dos operandos, crea un test para comprobar que los métodos de la clase llevan a cabo correctamente sus funciones. AUTOEVALUACIÓN En versiones anteriores a NetBeans 7.0., para poder trabajar con el FrameWork JUnit era necesario incorporarlo manualmente al IDE. Verdadero Falso Efectivamente, ya en la versión 7.0. no es necesario y al realizar la instalación se acepta la licencia de JUnit desde el inicio. Con lo que podremos utilizar este FrameWork directamente en nuestro NetBeans 7.0. ‐ 35 ‐ Uso de estructuras de control DAW 8. Depuración de programas CASO PRÁCTICO Ada y Juan ya conocen las capacidades del depurador que incorpora el entorno NetBeans y van a enseñar a María las ventajas de utilizarlo. – Puedes depurar tus programas haciendo dos cosas: creando Breakpoints o haciendo ejecuciones paso a paso. – Le comenta Juan. María, que estaba codificando un nuevo método, se detiene un momento y pregunta: – Entonces, ¿cuando el programa llega al Breakpoint podré saber qué valor tiene una variable determinada? – Efectivamente María, y podrás saber el valor de aquellas que tú decidas. De este modo a través de los puntos de ruptura y de las ejecuciones paso a paso podrás descubrir dónde puede haber errores en tus programas. Conocer bien las herramientas que el depurador nos ofrece es algo que puede ahorrarnos mucho trabajo. – Aporta Ada. La Depuración de programas es el proceso por el cual se identifican y corrigen errores de programación. Generalmente, en el argot de programación se utiliza la palabra debugging, que significa localización y eliminación de bichos (bugs) o errores de programa. A través de este proceso se descubren los errores y se identifica qué zonas del programa los producen. Hay tres etapas por las que un programa pasa cuando éste es desarrollado y que pueden generar errores: 9 Compilación: Una vez que hemos terminado de afinar un programa, solemos pasar generalmente cierto tiempo eliminando errores de compilación. El compilador de Java mostrará una serie de chequeos en el código, sacando a la luz errores que pueden no apreciarse a simple vista. Una vez que el programa es liberado de los errores de compilación, obtendremos de él algunos resultados visibles pero quizá no haga aún lo que queremos. 9 Enlazado: Todos los programas hacen uso de librerías de métodos y otros utilizan métodos generados por los propios programadores. Un método es enlazado (linked) sólo cuando éste es llamado, durante el proceso de ejecución. Pero cuando el programa es compilado, se realizan comprobaciones para saber si los métodos llamados existen y sus parámetros son correctos en número y tipo. Así que los errores de enlazado son detectados durante la etapa de compilación. 9 Ejecución: Cuando el programa entra en ejecución, es muy frecuente que éste no funcione como se esperaba. De hecho, es normal que el programa falle. Algunos errores serán detectados automáticamente y el programador será informado, como acceder a una parte de un array que no existe (error de índices) por ejemplo. Otros son más sutiles y dan lugar simplemente a comportamientos no esperados, debido a la existencia de errores ocultos (bugs) en el programa. De ahí los términos bug y debugging. El problema de la depuración es que los síntomas de un posible error son generalmente poco claros, hay que recurrir a una labor de investigación para encontrar la causa. La depuración de programas es algo así como ser doctor: existe un síntoma, hemos de encontrar la causa y entonces determinar el problema. El trabajo de eliminación de errores puede ser interesante. La depuración y la prueba suelen requerir una cantidad de tiempo considerable en comparación con el tiempo dedicado a la primera codificación del programa. Pero no te preocupes, es normal emplear más tiempo en este proceso. ¿Y cómo llevamos a cabo la depuración de nuestros programas?, pues a través del debugger o depurador del sistema de desarrollo Java que estemos utilizando. Este depurador será una herramienta que nos ayudará a eliminar posibles errores de nuestro programa. Podremos utilizar depuradores simples, como el jdb propio de Java basado en línea de comandos. O bien, utilizar el ‐ 36 ‐ Diseño de Aplicaciones Web Tema 4 depurador existente en nuestro IDE (en nuestro caso NetBeans). Este último tipo de depuradores muestra los siguientes elementos en pantalla: El programa en funcionamiento, el código fuente del programa y los nombres y valores actuales de las variables que se seleccionen. ¿Qué elementos podemos utilizar en el depurador? Existen al menos dos elementos fundamentales que podemos utilizar en nuestro debugger o depurador, son los siguientes: 9 Breakpoints o puntos de ruptura: Estos puntos pueden ser determinados por el propio programador a lo largo del código fuente de su aplicación. Un Breakpoint es un lugar en el programa en el que la ejecución se detiene. Estos puntos se insertan en una determinada línea del código, entonces el programa se pone en funcionamiento y cuando el flujo de ejecución llega hasta él, la ejecución queda congelada y un puntero indica el lugar en el que la ejecución se ha detenido. El depurador muestra los valores de las variables tal y como están en ese momento de la ejecución. Cualquier discrepancia entre el valor actual y el valor que deberían tener supone una importante información para el proceso de depuración. 9 Ejecución paso a paso: El depurador también nos permite ejecutar un programa paso a paso, es decir, línea por línea. A través de esta herramienta podremos seguir el progreso de ejecución de nuestra aplicación y supervisar su funcionamiento. Cuando la ejecución no es la esperada quizá estemos cerca de localizar un error o bug. En ocasiones, si utilizamos métodos procedentes de librerías estándar no necesitaremos hacer un recorrido paso a paso por el interior de éstos métodos, ya que es seguro que no contendrán errores internos y podremos ahorrar tiempo no entrando en su interior paso a paso. El debugger ofrece la posibilidad de entrar o no en dicho métodos. DEBES CONOCER Para completar tus conocimientos sobre la depuración de programas, te proponemos los siguientes enlaces en los que podrás encontrar cómo se llevan a cabo las tareas básicas de depuración a través del IDE NetBeans. Depuración de programas con NetBeans La depuración (debug) permite examinar las aplicaciones para buscar errores, ya que posibilita observar las líneas que se van ejecutando, así como los valores que van tomando las variables en cada paso. Para realizar la depuración de un programa, se debe establecer en primer lugar un punto de interrupción donde debe pararse la ejecución de la aplicación. Esto se consigue con alguna de las siguientes acciones sobre la línea de código en la que se desee establecer el punto de interrupción: 9 9 9 9 Clic en el margen izquierdo Menú contextual > "Ocultar/Mostrar línea de punto de interrupción" Pulsando la combinación de teclas: Ctrl + F8 Menú "Depurar > Ocultar/Mostrar línea de punto de interrupción" ‐ 37 ‐ Uso de estructuras de control DAW Al realizar alguna de esas acciones, se marca en color rosado la línea que se ha convertido en un punto de interrupción, y se muestra un pequeño cuadrado en el margen izquierdo. Una vez establecido al menos un punto de interrupción, se debe ejecutar la aplicación en modo depuración. Esto se puede llevar a cabo sobre el proyecto o sólo sobre el archivo actual: 9 9 Depurar archivo actual: Æ Menú contextual > "Debug nombreArchivo" Æ Menú "Depurar > Debug nombreArchivo" Æ Pulsando la combinación de teclas: Ctrl + Mayúsculas + F5 Depurar proyecto: Æ Menú "Depurar > Debug Main Project" Æ Icono "Debug Main Project" Al llegar la ejecución de la aplicación al punto de interrupción establecido, se destaca en color verde la línea de código en la que se encuentre la ejecución. En la parte inferior se muestra la ventana de observación de las variables locales, en la que se puede comprobar el valor que va tomando cada variable. A partir del momento en que se para la ejecución del programa se puede continuar con la ejecución línea a línea utilizando la opción "Continuar ejecución": 9 Pulsando la tecla F8 9 Menú "Depurar > Continuar ejecución" 9 Icono "Continuar ejecución" Así se va mostrando en verde la línea que se va ejecutando en cada momento, y se van actualizando en la ventana inferior los valores que van tomando las variables locales. En caso de que se desea que el programa continúe la ejecución sin más paradas, se dispone de la opción "Continuar": 9 9 9 Pulsando la tecla F5 Menú "Depurar > Continuar" Icono "Continuar" ‐ 38 ‐ Diseño de Aplicaciones Web Tema 4 Depuración básica en NetBeans. 1 2 3 ‐ 39 ‐ Uso de estructuras de control 4 5 6 ‐ 40 ‐ DAW Diseño de Aplicaciones Web Tema 4 7 8 9 ‐ 41 ‐ Uso de estructuras de control 10 11 12 ‐ 42 ‐ DAW Diseño de Aplicaciones Web Tema 4 13 14 15 ‐ 43 ‐ Uso de estructuras de control DAW PARA SABER MÁS Si deseas conocer algo más sobre depuración de programas, pero a un nivel algo más avanzado, accede al siguiente vídeo. http://www.youtube.com/watch?v=qAo9‐bWDzj0 El vídeo comienza con una descripción genérica sobre las funciones del depurador del entorno IDE NetBeans. Seguidamente se realiza una descripción de las herramientas principales del depurador, llevando a cabo ejemplos de depuración utilizando: Step into, Step Out, Step Over, Breakpoints (simples, condicionales, cuantificados), Watches y Call Stack. Como puede observarse se han utilizado una amplia gama de herramientas del depurador que pueden ser muy útiles para llevar el proceso de depuración con garantías. ‐ 44 ‐ Diseño de Aplicaciones Web Tema 4 9. Documentación del código CASO PRÁCTICO Ada está mostrando a Juan la documentación sobre una serie de métodos estándar que van a necesitar para completar el desarrollo de una parte de la aplicación. Esta documentación tiene un formato estructurado y puede accederse a ella a través del navegador web. – ¡Qué útil y fácil está siendo el acceso esta documentación! La verdad es que los que la han generado se lo han currado bastante. ¿Generar esta documentación se llevará mucho tiempo, no Ada? – Pregunta Juan mientras recoge de la impresora la documentación impresa. Ada prepara rápidamente una clase en blanco y comienza a incorporarle una serie de comentarios: – Verás Juan, documentar el código es vital y si incorporas a tu código fuente unos comentarios en el formato que te voy a mostrar, la documentación puede ser generada automáticamente a través de la herramienta Javadoc. Observa... – Responde Ada. Llegados a este punto, vamos a considerar una cuestión de gran importancia, la documentación del código fuente. Piensa en las siguientes cuestiones: 9 ¿Quién crees que accederá a la documentación del código fuente? Pues serán los autores del propio código u otros desarrolladores. 9 ¿Por qué hemos de documentar nuestro código? Porque facilitaremos su mantenimiento y reutilización. 9 ¿Qué debemos documentar? Obligatoriamente: clases, paquetes, constructores, métodos y atributos. Opcionalmente: bucles, partes de algoritmos que estimemos oportuno comentar, … A lo largo de nuestra vida como programadores es probable que nos veamos en la necesidad de reutilizar, modificar y mantener nuestro propio código o incluso, código de otros desarrolladores. ¿No crees que sería muy útil que dicho código estuviera convenientemente documentado? ¿Cuántas veces no hemos leído código de otros programadores y quizá no hayamos comprendido qué estaban haciendo en tal o cual método?. Como podrás comprender, la generación de una documentación adecuada de nuestros programas puede suponer una inestimable ayuda para realizar ciertos procesos en el software. Si analizamos la documentación de las clases proporcionada en los paquetes que distribuye Sun, nos daremos cuenta de que dicha documentación ha sido generada con una herramienta llamada Javadoc. Pues bien, nosotros también podremos generar la documentación de nuestro código a través de dicha herramienta. Si desde el principio nos acostumbramos a documentar el funcionamiento de nuestras clases desde el propio código fuente, estaremos facilitando la generación de la futura documentación de nuestras aplicaciones. ¿Cómo lo logramos? A través de una serie de comentarios especiales, llamados comentarios de documentación que serán tomados por Javadoc para generar una serie de archivos HTML que permitirán posteriormente, navegar por nuestra documentación con cualquier navegador web. Los comentarios de documentación tienen una marca de comienzo (/**) y una marca de fin (*/). En su interior podremos encontrar dos partes diferenciadas: una para realizar una descripción y otra en la que encontraremos más etiquetas de documentación. Veamos un ejemplo: ‐ 45 ‐ Uso de estructuras de control DAW /** * Descripción principal (texto/HTML) * * Etiquetas (texto/HTML) */ Este es el formato general de un comentario de documentación. Comenzamos con la marca de comienzo en una línea. Cada línea de comentario comenzará con un asterisco. El final del comentario de documentación deberá incorporar la marca de fin. Las dos partes diferenciadas de este comentario son: 9 Zona de descripción: es aquella en la que el programador escribe un comentario sobre la clase, atributo, constructor o método que se vaya a codificar bajo el comentario. Se puede incluir la cantidad de texto que se necesite, pudiendo añadir etiquetas HTML que formateen el texto escrito y así ofrecer una visualización mejorada al generar la documentación mediante Javadoc. 9 Zona de etiquetas: en esta parte se colocará un conjunto de etiquetas de documentación a las que se asocian textos. Cada etiqueta tendrá un significado especial y aparecerán en lugares determinados de la documentación, una vez haya sido generada. En la siguiente imagen puedes observar un ejemplo de un comentario de documentación. R. Caron.: "do not document bad code ­ rewrite it" REFLEXIONA Documentar el código de un programa es añadir suficiente información como para explicar lo que hace, punto por punto, de forma que no sólo los ordenadores sepan qué hacer, sino que además los humanos entiendan qué están haciendo y por qué. Documentar un programa no es sólo un acto de buen hacer del programador por aquello de dejar la obra rematada. Es además una necesidad que sólo se aprecia en su debida magnitud cuando hay errores que reparar o hay que extender el programa con nuevas capacidades o adaptarlo a un nuevo escenario. 9.1 Etiquetas y posición Cuando hemos de incorporar determinadas etiquetas a nuestros comentarios de documentación es necesario conocer dónde y qué etiquetas colocar, según el tipo de código que estemos documentando en ese momento. Existirán dos tipos generales de etiquetas: 1. Etiquetas de bloque: Son etiquetas que sólo pueden ser incluidas en el bloque de documentación, después de la descripción principal y comienzan con el símbolo @. 2. Etiquetas en texto: Son etiquetas que pueden ponerse en cualquier punto de la descripción o en cualquier punto de la documentación asociada a una etiqueta de bloque. Son etiquetas definidas entre llaves, de la siguiente forma {@etiqueta} ‐ 46 ‐ Diseño de Aplicaciones Web Tema 4 En la siguiente tabla podrás encontrar una referencia sobre las diferentes etiquetas y su ámbito de uso. 9.2. Uso de las etiquetas ¿Cuáles son las etiquetas típicas y su significado? Pasaremos seguidamente a enumerar y describir la función de las etiquetas más habituales a la hora de generar comentarios de documentación. 9 @autor texto con el nombre: Esta etiqueta sólo se admite en clases e interfaces. El texto después de la etiqueta no necesitará un formato especial. Podremos incluir tantas etiquetas de este tipo como necesitemos. 9 @version texto de la versión: El texto de la versión no necesitará un formato especial. Es conveniente incluir el número de la versión y la fecha de ésta. Podremos incluir varias etiquetas de este tipo una detrás de otra. 9 @deprecated texto: Indica que no debería utilizarse, indicando en el texto las causas de ello. Se puede utilizar en todos los apartados de la documentación. Si se ha realizado una sustitución debería indicarse qué utilizar en su lugar. Por ejemplo: @deprecated El metodoCorrecto} método no funciona correctamente. Se recomienda el uso de {@ling 9 @exception nombre‐excepción texto: Esta etiqueta es equivalente a @throws. 9 @param nombre‐atributo texto: Esta etiqueta es aplicable a parámetros de constructores y métodos. Describe los parámetros del constructor o método. Nombre‐atributo es idéntico al nombre del parámetro. Cada etiqueta @param irá seguida del nombre del parámetro y después de una descripción de éste. Por ejemplo: 9 @return texto: Esta etiqueta se puede omitir en los métodos que devuelven void. Deberá aparecer en todos los métodos, dejando explícito qué tipo o clase de valor devuelve y sus posibles rangos de valores. Veamos un ejemplo: @param fromIndex El índice del primer elemento que debe ser eliminado. /** * Chequea si un vector no contiene elementos. * * @return <code>verdadero</code>si solo si este vector no contiene componentes, esto es, su tamaño es cero; * <code>falso</code> en cualquier otro caso. */ public boolean VectorVacio() { return elementCount == 0; } 9 @see referencia: Se aplica a clases, interfaces, constructores, métodos, atributos y paquetes. Añade enlaces de referencia a otras partes de la documentación. Podremos añadir a la etiqueta: cadenas de caracteres, enlaces HTML a páginas y a otras zonas del código. Por ejemplo: ‐ 47 ‐ Uso de estructuras de control * a * * DAW @see "Diseño de patrones: La reusabilidad de los elementos de la programación orientada objetos” @see <a href="http://www.w3.org/WAI/">Web Accessibility Initiative</a> @see String#equals(Object) equals 9 @throws nombre‐excepción texto: En nombre‐excepción tendremos que indicar el nombre completo de ésta. Podremos añadir una etiqueta por cada excepción que se lance explícitamente con una cláusula throws, pero siguiendo el orden alfabético. Esta etiqueta es aplicable a constructores y métodos, describiendo las posibles excepciones del constructor/método. AUTOEVALUACIÓN ¿Qué etiqueta podría omitirse en un método que devuelve void? @param @throws @return @return no sería necesaria al no devolver nada el método. 9.3. Orden de las etiquetas Las etiquetas deben disponerse en un orden determinado, es el siguiente: etiqueta @autor @version @param @return @exception @throws @see Orden de las etiquetas en comentarios de documentación Descripción En clases e interfaces. Se pueden poner varios. Es mejor ponerlas en orden cronológico. En clases e interfaces. En métodos y constructores. Se colocarán tantos como parámetros tenga el constructor o método. Mejor en el mismo orden en el que se encuentren declarados. En métodos. En constructores y métodos. Mejor en el mismo orden en el que se han declarado, o en orden alfabético. Es equivalente a @exception. Podemos poner varios. Comenzaremos por los más generales y después los más específicos. @deprecated PARA SABER MÁS Si quieres conocer cómo obtener a través de Javadoc la documentación de tus aplicaciones, observa el siguiente código: /* * ejemplojavadoc.java * * Created on July 5, 2003, 4:24 AM */ /** * Clase que comienza la estructura de escepciones * @author Roberto Canales * @since 1.0 * @see Visitar www.adictosaltrabajo.com */ class RCException extends Exception { void depura(String psError) { System.out.println("Error: " + psError); } ‐ 48 ‐ Diseño de Aplicaciones Web Tema 4 RCException(String psError) { super(psError); depura(psError); } } /** * * @author Roberto Canales * @since 1.0 * @see Visitar www.adictosaltrabajo.com */ public class ejemplojavadoc { /** Constantes publicas public static final int public static final int public static final int de gestion errores*/ ERROR = 0; LOG = 1; INFO = 2; /** Constructor por defecto */ public ejemplojavadoc() { } void depura(String sError) { System.out.println("ejemplojavadoc: " + sError); } /** * @param args Array de argumentos */ public static void main(String[] args) { /** Construimos un objeto no estático */ ejemplojavadoc objetoAuxiliar = new ejemplojavadoc(); try { objetoAuxiliar.ejecuta(); } catch(RCException e) { objetoAuxiliar.depura("Excepcion = " + e.getMessage()); } } /** * Punto de entrada a la aplicación * @exception RCException Se genera una excepción genérica. * @return true */ public boolean ejecuta() throws RCException { /** Retornamos true por defecto */ int error = 0; if(error == 0) { throw new RCException("Invocamos excepciones"); } return true; } } Documentación de clases con Javadoc Con el fin de facilitar la compresión de uso de una clase y sus métodos, éstos deben estar debidamente documentados informando de su funcionamiento, de los parámetros que se deben utilizar y de los resultados que se obtienen. ‐ 49 ‐ Uso de estructuras de control DAW Para facilitar esta tarea, Java dispone de la herramienta javadoc, que genera una documentación estandarizada obteniéndose en formato web, semejante a la API oficial de Java. Se debe seguir un modelo concreto para que se genere la documentación de forma correcta: 9 9 Todos los comentarios deben comenzar por /** y terminar con */ Se debe documentar la clase y cada método, escribiendo un comentario delante de cada uno de ellos. 9 Dentro del comentario se pueden utilizar etiquetas HTML. 9 El comentario comenzará con una descripción general del objetivo de la clase y de los métodos. 9 Después se pueden indicar una serie de valores utilizando unas etiquetas predefinidas, siendo las más importantes las siguientes: Æ @author: Para indicar el nombre del autor de la clase o método. Æ @version: Permite especificar la versión de la clase o método. Æ @param: Descripción de cada parámetro del método. Æ @return: Descripción del valor que retorna el método. Æ @throws: Excepción que puede lanzar el método. 01./** 02.* Aquí se debe escribir una descripción general del funcionamiento de la clase 03.* 04.* @author nombre del autor 05.* @version 1.0 06.*/ 07.public class ClaseEjemploJavadoc { 08. 09./** atributo1 sirve para lo que sea */ 10.public String atributo1; 11.private int atributo2; 12. 13./** 14.* Descripción del método constructor 15.* 16.* @param atributo1 Descripción del primer parámetro 17.* @param atributo2 Descripción del segundo parámetro 18.*/ 19.ClaseEjemploJavadoc(String atributo1, int atributo2) { 20.this.atributo1 = atributo1; 21.this.atributo2 = atributo2; 22.} 23. 24./** 25.* Descripción del método método1 26.* 27.* @param parámetro3 Descripción del valor que debe pasarse como parámetro 28.* @return Descripción del valor que retorna el método al ser llamado 29.*/ 30.public int método1(int parámetro) { 31.return 1; 32.} 33.} El entorno NetBeans proporciona una forma sencilla de generar la documentación en formato HTML a través de javadoc. Para ello se puede utilizar el menú Ejecutar > Generar Javadoc, o desde el menú contextual del proyecto. ‐ 50 ‐ Diseño de Aplicaciones Web Tema 4 Al generar la documentación se abre la página web que la contiene, que tendrá el siguiente estilo: Para comprobar si se ha incluido toda la información necesaria o para facilitar la inclusión de los comentarios, NetBeans ofrece la herramienta Analizador Javadoc: Herramientas > Analizar Javadoc, que abre una ventana informando de la información que falta y la posibilidad de solucionar los problemas encontrados. ‐ 51 ‐