Primeros Pasos JAVA
Primeros Pasos JAVA
Primeros Pasos JAVA
Primeros pasos
Hasta el momento hemos realizado una introducción a Java indicando como instalarlo y configurarlo. En este segundo módulo se pretende profundizar en el lenguaje Java y
empezar a realizar unos primeros algoritmos que nos permitan introducirnos de lleno en la programación orientada a objetos en el capítulo 3.
Elementos de un programa
Elementos de un programa
En el módulo 1 ya hemos realizado un programa y hemos visto algunas palabras clave y hablado de clases y paquetes pero es ahora cuando vamos a profundizar en las
posibilidades del lenguaje Java
Separadores
Separadores
En Java utilizaremos los siguientes separadores:
Con anterioridad ya hemos utilizado todos ellos y conforme avancemos en el curso vamos a ir viendo mas ejemplos de su uso. Vamos a ver un pequeño recordatorio de donde
los hemos utilizado:
Cuando definimos una variable llamada args que era un vector de Strings utilizamos los corchetes: String[] args.
Cuando definimos la clase Modulo1HolaMundo ya utilizamos las llaves para definir el alcance de la clase: public class Modulo1HolaMundo { (...) }.
Creando creamos el método main hicimos uso para los paréntesis para indicar el comienzo y fin de los parámetros: public static void main(String[] args) {.
Al finalizar la sentencia System.out.println("Hola mundo"); hicimos uso del punto y coma para delimitar el fin de la misma.
En la misma sentencia que en el caso anterior System.out.println("Hola mundo"); hicimos uso del punto para acceder a una clase y sus objetos. En este apartado
entraremos en mayor profundidad mas adelante.
El caracter coma aún no lo hemos utilizado, pero podríamos darle uso en el siguiente ejemplo: void nombreFuncion(int param1, int param2); Aquí la función de la coma no
es otra mas que separar los parámetros param1 y para2 del método nombreFuncion.
Pregunta VerdaderoFalso
Verdadero Falso
Falso
Para delimitar el contenido de una clase se hace uso de las llaves {} Ocurre lo mismo con los métodos.
Verdadero Falso
Falso
El punto y coma solo debe colocarse al final de las sentencias. Cuando declaramos una clase o método no hay que hacerlo.
Verdadero Falso
Falso
Operadores
Se hace necesario poder realizar cálculos o tomar decisiones con los datos que manejamos, es por ello que nos surge la necesidad de disponer de operadores que nos permitan
hacerlo. A continuación procedo a enumerar los operadores mas habituales:
En Java existen mas operadores que los aquí indicados pero creo que con los aquí señalados es mas que suficiente para cubrir los objetivos de este curso. A lo largo del curso
se procurará utilizar todos los operadores aquí indicados para así aclarar cualquier posible duda que pudiera existir con ellos.
Comentarios
Comentarios
Los comentarios los introduciremos en nuestro código fuente para facilitar la lectura y comprensión posterior del código. La redacción de estos comentarios también van a facilitar
en la posterior elaboración de la documentación del código.
¿Cómo se indica en un programa que algo es un comentario? Existen distintos modos de hacerlo:
Comentarios de línea: Todo lo que, en una línea, esté detrás del símbolo // se considerará un comentario y ni el compilador ni el intérprete lo tendrán en cuenta.
Comentarios de bloque: Todo lo que esté comprendido entre el símbolo /* y el símbolo */ se considerá un comentario y ni el compilador ni el intérprete lo tendrán en
cuenta.
Comentarios de documentación: Todo lo que esté comprendido entre el símbolo /** y el símbolo */ se considerará un comentario de documentación y en la generación de
documentación y en la autoayuda del IDE netbeans nos proporcionará información extra.
Entre las líneas 230 y 242 tenemos un comentario de documentación. En este tipo de comentarios, además de explicar para que sirve una función se puede detallar información
adicional a través de anotaciones como @param @return o @throws que sirven respectivamente para indicar los parámetros de la función, lo que devuelve la función y el tipo de
excepción o excepciones que lanza la función.
Es muy importante concienciarnos a nosotros/as y a nuestro alumnado de la importancia de documentar el código para que quede reflejada la funcionalidad del código escrito y
así facilitar su posterior mantenimiento.
Constantes y variables
Constantes y variables
Una variable es un lugar en memoria donde almacenaremos un dato que podrá cambiar o no a lo largo de la ejecución de nuestros programas. Todas las variables tienen que
ser de un determinado tipo y tener un nombre. Por convenio las variables tienen al menos el primer caracter de su nombre en minúsculas. Una constante es un lugar en
memoria en el cual almacenaremos un dato con el fin único de leerlo y sin posibilidad de modificación. Las constante deben tener un determinado tipo y deben tener un nombre.
Por convenio el nombre de las constantes se escribe en mayúsculas. En java para definir una constante lo haremos exactamente igual que si definieramos una variable pero las
constantes deben ser precedidas por la palabra reservada final.
Anteriormente hemos indicado que tanto las constantes como las variables deben ser de un determinado tipo, a continuación vamos a hablar de ellos.
En java existen 2 tipos de variables: los tipos básicos (también llamados tipos primitivos) y los objetos. De los objetos nos ocuparemos en el módulo 3 por lo que a
continuación paso a enumerar los tipos primitivos mas habituales.
Números enteros:
byte: utiliza 8 bits en memoria. Su rango va de 27 a 271
short: utiliza 16 bits en memoria. Su rango va de 215 a 2151
int: utiliza 32 bits en memoria. Su rango va de 231 a 2311
long: utiliza 64 bits en memoria. Su rango va de 263 a 2631
Números decimales:
float: utiliza 32 bits.
double: utiliza 64 bits.
Booleanos:
boolean: utiliza 1 bit. Solo puede valer true (verdadero) o false (falso)
Cadenas:
char: utiliza 16 bits.
int operando1 = 4; // Declaramos una variable llamada operando1 de tipo int y le asignamos el valor 4
final double PI = 3.1416; // Declaramos una constante de tipo double. El nombre de la constante es PI y le asignamos el valor 3,1416
boolean esMayor = false;//Declaramos una varible de tipo boolean, con nombre esMayor y le asignamos el valor falso
final char CARACTER = 'a';// Declaramos una costante de tipo char y nombre CARACTER. Le asignamos el valor 'a'. Fíjate en que son comillas simples.
Aunque lo veremos en el siguiente módulo del curso a continuación vamos a crear unas variables que harán referencias a objetos. Del código que aparece a continuación me
interesa que nos fijemos en que declaremos tipos primitivos u objetos la sintaxis es prácticamente la misma:
Integer operando1 = new Integer(4); // Declaramos una variable llamada operando1 de tipo Integer y le asignamos el valor 4
final Double PI = new Double(3.1416); // Declaramos una constante de tipo Double. El nombre de la constante es PI y le asignamos el valor 3,1416
Boolean esMayor = new Boolean(false); // Declaramos una variable de tipo Boolean, con nombre esMayor y le asignamos el valor falso.
final String CADENA = "a";// Declaramos una constante de tipo String y nombre CADENA y le asignamos el valor "a". Fíjate en que son comillas dobles. Además aquí es el único l
Como podemos intuir en base a estos ejemplos cada tipo básico tiene asociado un objeto equivalente. Pero como vemos a continuación (y profundizaremos en el módulo 3)
también podemos crear variables del tipo de Objetos que hayamos creado.
Coche miCoche = new Coche(); //Declaramos una variable de tipo Coche con el nombre miCoche y llamamos al constructor de la clase. Mas adelante hablaremos de esto
Moto moto1 = null; //Declaramos una variable de tipo Moto con el nombre moto1 y le asignamos el valor null
Si eres observador/a te habrás dado cuenta de que los tipos básicos empiezan en minúscula mientras que los objetos comienzan en mayúsculas. Es probable que también te
hayas percatado de que el nombre que asigno a las variables siempre comienza en minúsculas y el nombre que asigno a las constantes está completamente en mayúsculas,
esto son convenios de escritura del lenguaje Java y tu puedes seguir tu propio estilo de código pero es interesante hacer uso del convenio porque facilita la lectura y comprensión
del código yen caso de trabajar con otras personas se es mas productivo. En este módulo, un poco mas adelante, hablaremos en mayor profundidad de esta cuestión.
Ámbito
Ámbito
Las variables y constantes tienen asociado un ámbito. Simplificando, el ámbito indica donde existen y por tanto pueden utilizarse. A continuación voy a tratar de explicarlo con un
extracto de código.
En el código que tenemos en la imagen anterior en la línea 6 declaramos la variable variableClase cuyo ámito es toda la clase, es decir, desde cualquier punto de la clase
podríamos acceder a ella. En la línea 8 declaramos la variable variableMetodo, el ámbito de esta variable es el método main, es decir, puede ser accedida desde dentro del main
pero no en otros métodos de la clase. En la línea 10 declaramos otra variable llamada variableCondicion cuyo ámbito es el bucle if, no es accesible desde ningún otro lugar. En la
línea 12 declaramos la variable de nombre i que es accesible dentro de todo el bucle. En la línea 13 declaramos la variable variableBucle con la que ocurre lo mismo que con i.
En la línea 14 declaramos la variable j cuyo ámbito es el bucle anidado y es únicamente accesible desde este bucle pero no del otro. Lo mismo ocurre en la línea 15 con la
variable variableOtroBucle.
Pregunta VerdaderoFalso
En el ejemplo de código anterior, podría sustituir la línea 10 por System.out.println(variableClase); ya que la variable variableClase es accesible desde la línea 10
Verdadero Falso
Verdadero
variableClase es accesible desde toda la clase Modulo2Ambito y la línea 10 está dentro de la clase por lo que es accesible.
En el ejemplo de código anterior, podría añadir al final de la línea 6 System.out.println(variableBucle); ya que la variable variableBucle es accesible desde la línea 6
Verdadero Falso
Falso
variableBucle solo está accesible dentro del bucle que está entre las líneas 12 y 17 por lo que no es accesible en la línea 6 y obtendríamos un error de compilación.
Cadenas
Cadenas
Hasta el momento hemos trabajado con cadenas (String) en alguna ocasión. Hemos mostrado por pantalla una cadena:
System.out.println("Hello world!");
final String CADENA = "a";// Declaramos una constante de tipo String y nombre CADENA y le asignamos el valor "a". Fíjate en que son comillas dobles.
String texto = "Hola mundo";// Declaramos una variablede tipo String y nombre textoy le asignamos el valor "Hola mundo". Fíjate en que son comillas dobles.
String no es un tipo primitivo, String es una clase por lo que cada vez que hacemos uso de ella estamos creando un objeto.
Como ya vimos en este módulo en el apartado de constantes y variables y como veremos en el siguiente módulo de este curso que cada vez que creamos un objeto lo hacemos
con la sintaxis Clase nombreVariable = new Clase();. Sin embargo según acabo de indicar si utilizamos String estamos creando un objeto ¿entonces porque aquí no usamos new
y hacemos la asignación directamente? Vamos a ver un par de ejemplos:
En un entorno profesional no se usaría la clase String sino que se usarían las clases StringBuffer o StringBuilder (en función de las necesidades específicas). En el curso
utilizaremos la clase String pero por curiosidad vamos a ver un ejemplo de código con estas clases:
Arrays
Arrays
En Java existen un tipo de variables llamadas Arrays que nos permiten crear vectores de un mismo elemento. Es importante indicar que un Array es un objeto.
int[] array1 = new int[4]; // Creamos una variable llamada array1 que tendrá 4 posiciones
int array2[] = new int[4]; // Creamos una variable llamada array2 que tendrá 4 posiciones
int[] array3 = {1, 2, 3}; // Creamos una variable llamada array3 que en su posición 0 tendrá un 1, en su posición 1 tendrá un 2 y en la posición 2 tendrá un 3
Cuando creamos un Array como es el caso de array1 y array2 y lo inicializamos pero no definimos el valor de sus posiciones estas toman el valor por defecto de la variable, en
nuestro caso 0.
La primera posición de un Array es la posición 0. En caso de intentar acceder a una posición inexistente obtendremos una excepción (se tratan mas adelante)
De un modo análogo al anterior podemos crear Arrays de Arrayx (matrices). A continuación podemos ver un ejemplo:
int[][] matriz = new int[10][10];// Creamos una variable llamada matriz que es una matriz de enteros de 10x10
Si queremos acceder al valor de un array debemos hacerlo con la sintaxis nombreVariable[posicion]. A continuación unos ejemplos:
false
true
false
Cuando lleguemos al apartado de control de flujo realizaremos mas ejemplos con Arrays.
Control de flujo
Control de flujo
Además de poder operar con los datos tenemos la necesidad de que ocurran cosas distintas en función de los mismos. Para cubrir estas necesidades dispondremos de
funciones condiciones y bucles.
if/else if/else
switch
for
while
do while
En los nodo inferiores voy a tratar de explicarlos y veremos algunos ejemplos con código.
Funciones condicionales
Funciones condicionales
Existen 2 funciones condicionales: if/else if/else y switch.
Vamos a comenzar por la estructura if/else if/else. En esta estructura la sintaxis es la siguiente:
if(condicion){
sentencias;
}else if(condicion){
sentencias;
}else{
sentencias;
}
De la estructura anterior es obligatorio que exista siempre el if. else if puede haber 0 o varios. else puede haber 1 o 0. Y el funcionamiento es el siguiente. Cuando el compilador
llega a la condición del if y la evalúa, si la condición es verdadera ejecutará las sentencias ubicadas dentro del if y habrá terminado con la estructura if/else if/else, ya no ejecutará
sentencias de otros bloques aunque estas sean verdad. Si la condición del if es falsa se evalúa la condición del else if y si es verdadera se ejecutan las sentencias ubicadas
dentro, en caso de ser falsa se evalúa el siguiente else if si lo hubiera. Si la condición de algún else if fuese verdadera se ejecutarían las sentencias de su interior y ya no se
evaluarían ni ejecutarían mas condiciones de toda la estructura if/else if/else. En caso de que ninguna condición del if o los else if fuese verdadera y hubiese un bloque else se
ejecutarían las sentencias contenidas dentro del bloque else.
Vamos a ver a continuación un ejemplo de 2 estructuras if/else if/else ya que es mas sencillo comprender esta estructura leyendo el código que tratando de explicarlo.
Cuando el programa llega al if de la línea 8 se comprueba si la variable calificacion es mayor o igual a 0 (lo es) y que la variable calificacion sea menor a 5 (no lo es). Como el
resultado de true && false es false no entramos dentro de sus llaves y se pasa a evaluar la condición de la línea 11. En la línea 11 se evalúa si la variable calificacion es menor a
7 (no lo es), al ser falsa se pasa a evaluar la condición de la línea 13. En la línea 13 se evalúa si la variable calificacion es menor a 9 (lo es), al ser verdad se ejecutan todas las
sentencias ubicadas dentro de sus llaves, en ese caso solo hay 1 sentencia y se escribe Notable en consola. Como la condición de la línea 13 es verdad ya no se comprueban
las condiciones de las líneas 15, 17 o 19 y se salta directamente a la línea 22.
En la línea 22 tenemos otra condición así que se evalúa si la variable avisarFamilia es true (no lo es), al ser falso no se ejecuta el código de su interior y al no haber ningún else if
ni else se da por terminado este if.
condicion?valorSiCondicionVerdadera:valorSiCondicionFalsa;
Vamos a ver un ejemplo que sustituiría al código comprendido entre las líneas 22 a 24 de la imagen anterior
Se va a escribir algo por pantalla ¿el qué? dependerá del resultado que produzca la variable avisarFamilia, si la variable avisarFamilia es verdadero se devolverá "Avisar a la
familia" y será eso lo que se escriba. Si la variable avisarFamilia es falso se devolverá lo que está tras los 2 puntos, es decir, "" y se escribirá una línea vacía.
Una vez vista la estructura if/else if/else vamos a continuar con la estructura switch. Su sintaxis es la siguiente:
switch(expresión){
case valor1:
Sentencias;
break;
case valor2:
Sentencias;
break;
default:
Sentencias;
}
De la sintaxis anterior es obligatorio utilizar la primera línea y la última y debe haber al menos 1 case con sus sentencias y un break tras las sentencias. El elemento default es
opcional. Como quizás resulte algo complejo de explicar teóricamente vamos a ver un ejemplo:
En la línea 7 indicamos a nuestro switch que la variable de referencia es cadena. En la línea 8 comprobamos si "Hola" es igual a cadena y como no lo es pasamos al siguiente
case, al de la línea 11. En la línea 11 se evalúa si la variable cadena es igual a "Adios" y como lo es entramos a ejecutar todas las sentencias ubicadas dentro de nuestro case, en
este caso la de la línea 12. Luego llegamos a la línea 13, donde nos encontramos un break, este break nos lanza fuera del switch, a la línea 16. Si olvidásemos añadir el break de
la línea 13 se ejecutaría la sentencia de la línea 12 y luego la sentencia de la línea 15 por ello hay que finalizar cada case con break.
Si hablamos de la eficiencia interna de cada una de estas estructuras condicionales la documentación de Java indica que es mas óptimo hacer uso de switch si bien es cierto
que en los desarrollos que realicemos en el aula con nuestro alumnado no vamos a notar la diferencia de rendimiento.
Bucles
Bucles
Ha llegado el momento de hablar de los bucles y de sus distintas formas en Java.
Lo primero es definir que es un bucle, en la wikipedia podemos encontrar la siguiente definición de bucle:
“ Un bucle o ciclo, en programación , es una sentencia que se realiza repetidas veces a un trozo aislado de código, hasta que la condición asignada a dicho bucle
deje de cumplirse.
https://es.wikipedia.org/wiki/Bucle_(programaci%C3%B3n)
Ahora que sabemos lo que es vamos a ver los distintos bucles existentes en Java. Vamos a comenzar con el bucle for. Su sintaxis es la siguiente:
En iniciacion deberemos establecer el valor inicial que queremos dar a nuestra variable de control. En condicionFin deberá haber alguna condición lógica y en
accionSobreIniciacion deberemos establecer que queremos que pase tras cada iteracción. En sentencias estableceremos las sentencias de código que necesitemos. No se
considera una buena práctica modificar la variable de iniciación en las sentencias. Una vez mas, vamos a reforzar la explicación con un ejemplo que incluya código con el fin de
facilitar la compresión.
Vamos a analizar esta pieza de código. En la línea 6 creamos un array de 4 posiciones (tal como vimos en el apartado Arrays). En la línea 7 tenemos un bucle for y en el nos
encontramos int i = 0, esto hace que solo la primera vez que se accede al bucle se cree una variable llamada i que valga 0. Posteriormente se evalúa la condición array1.length
(nos devuelve la longitud del array) y como es verdad (0 es menor que 4) se procede a ejecutar las sentencias del interior del for. En este caso se trata de una única sentencia
que lo que hace es establecer un valor en la posición del array. Una vez se han ejecutado todas las sentencias de dentro de bucle for se ejecuta i++ y se reevalúa la condición, si
esta es cierta se vuelven a ejecutar las sentencias del bucle y así hasta el momento en que la condición sea falsa, momento en el cual se sale del bucle. En la línea 10 escribimos
por pantalla un corchete y posteriormente, en el bucle, recorremos las posiciones del array mostrando su valor y además en caso de que no se trate de la última posición del
array añadimos una coma. Cuando termina el bucle se añade el cirre del corchete antes escrito. Voy a escribir lo que ocurre en el primer bucle for de un modo menos prosaico a
continuación:
2º Se comprueba que la variable i (que vale 0) sea menor a array1.length (que vale 4). Es verdad.
5º Se comprueba que la variable i (que vale 1) sea menor a array1.length (que vale 4). Es verdad.
8º Se comprueba que la variable i (que vale 2) sea menor a array1.length (que vale 4). Es verdad.
11º Se comprueba que la variable i (que vale 3) sea menor a array1.length (que vale 4). Es verdad.
12º Ejecuto array1[i] = 10 * i; es decir, en la posición 3 del array1 pongo el resultado de multiplicar 10 * 3.
13º Hago i++. i pasa a valer 4.
14º Se comprueba que la variable i (que vale 4) sea menor a array1.length (que vale 4). Es falso, se sale del bucle.
En Java existe otra manera de trabajar con bucles for, vamos a ver la sintaxis a continuación pero veremos ejemplos en el apartado de estructuras de almacenamiento de datos.
Una vez hemos visto las posibilidades que nos ofrece el bucle for vamos a ver los bucles while. Los bucles while tienen la siguiente sintaxis:
while(condicion){
sentencias;
}
En un bucle while las sentencias de su interior se van a estar ejecutando siempre mientras la condición del while sea verdadera. Por ello, salvo que queramos hacer un bucle
infinito, en las sentencias actuaremos sobre la variable o variables que participen en la condición. Vamos a ver un ejemplo:
Lo que ocurre en el código de la imagen es lo siguiente. En la línea 6 creamos una variable de tipo entero con valor 10. En la línea 7 se evalúa que la variable antes creada sea
mayor o igual a 0. Si es verdad, se ejecutan las sentencias de las líneas 8 y 9. Si es falso, se sale del bucle while.
En último lugar vamos a hablar de los bucles dowhile. Estos bucles tienen la siguiente sintaxis:
do{
sentencias;
}while(condicion);
Los bucles dowhile son prácticamente iguales a los bucles while con la salvedad de que en un bucle dowhile las sentencias contenidas dentro del mismo se van a ejecutar
siempre 1 vez y luego se seguirán ejecutando mientras la condición sea verdadera. Al igual que en el caso anterior, salvo que queramos hacer un bucle infinito, en las sentencias
deberemos actuar sobre la variable o variables que participen en la condición.
Vamos a analizar que sucede en este código. En la línea 6 creamos una variable de tipo String con el valor a. En la línea 7 mostramos en una línea el valor de nuestra variable
cadena. Entre las líneas 8 y 10 nos encontramos un bucle dowhile, procedemos ejecutando todo lo que está dentro del bucle por lo que a nuestra variable cadena le añadimos
una e al final, ahora evaluamos la condición. Si la condición es cierta volvemos a ejecutar todas las sentencias contenidas dentro del dowhile. Si la condición es falsa hemos
terminado con el dowhile. En la línea 11 mostramos en una línea el valor de nuestra variable cadena. Entre las líneas 12 y 14 nos encontramos otro bucle dowhile, así que antes
de nada ejecutamos las sentencias de su interior, en este caso a nuestra variable cadena le añadimos una i al final y una vez hemos ejecutado las sentencias procedemos a
evaluar la condición.Si la condición es cierta volvemos a ejecutar todas las sentencias contenidas dentro del dowhile. Si la condición es falsa hemos terminado con el dowhile.
En la línea 15 mostramos en una línea el valor de nuestra variable cadena.
Presta atención a este detalle: Para conocer el tamaño de un array utilizamos nombreVariableDeTipoArray.length mientras que para conocer la longitud de una cadena utilizamos
nombreVariableTipoString.length(). La diferencia radica en el uso del paréntesis. Es algo que en nuestros primeros pasos con Java puede ocasionarnos algún pequeño trastorno.
Funciones
Funciones
En este apartado vamos a hablar de las funciones, también llamadas procedimientos, y vamos a nombrar los métodos pero estos últimos los veremos en mayor profundidad
en el módulo 3.
Una función es un trozo de código definido por un nombre a la cual se le pueden pasar parámetros o no y que puede o no devolver un valor.
Como primera aproximación a los métodos vamos a indicar que son algo muy parecido a una función pero ligado a un objeto. En el siguiente módulo profundizaremos en los
métodos.
Y vamos a ver que hacemos y porqué. Lo primero es indicar que ambos códigos hacen lo mismo como podemos ver en la salida del programa sin embargo en la 2ª imagen entre
las líneas 6 y 8 creamos una función que devuelve un float, tiene por nombre hazMedia y necesita 2 parámetros de tipo float. Esta función realiza la media de ambos datos y la
retorna. En el segundo programa, en las líneas 13 y 17, vemos que para llamar a esta función es suficiente con indicar a que variable vamos a asignarle el valor devuelto y
facilitar las variables con las que queremos que se haga el cálculo. Este ejemplo es trivial, pero si pensásemos en funciones mas complejas veríamos que al sacar factor común
del código repetido este queda mucho mas simple y legible, además, si utilizamos una función estamos siguiendo el principio DRY (Don't Repeat Yourself, no te respitas) que nos
va a permitir el que en caso de tener que realizar un cambio en el algoritmo únicamente haya que hacerlo en la función y no en todos los sitios donde aparezca el código no
llevado a la función.
“ En programación, una estructura de datos es una forma particular de organizar datos en una computadora para que pueda ser utilizado de manera eficiente.
https://es.wikipedia.org/wiki/Estructura_de_datos
En capítulos anteriores ya hemos trabajado con una estructura de datos, los Arrays (los cuales nos permitían almacenar datos en vectores).
Trabajar con Arrays puede ser suficiente para nuestras prácticas de aula pero conviene conocer las interfaces List, Map y Set. En el siguiente módulo del curso veremos que es
una interface pero ahora nos interesan conocer algunas implementaciones de las interfaces antes mencionadas. ArrayList, HashMap y HashSet son, respectivamente, algunas de
las implementaciones de estas interfaces.
Vamos a ver para que usar cada una de estas estructuras de datos:
Arrays (vectores): Es la forma mas eficiente de almacenar objetos pero una vez defines el tamaño del vector no puedes ampliarlo o reducirlo. Además no puedes guardar
variables de distinto tipo
List: Almacena las variables en el orden en que se insertan. Nos permite tener valores duplicados en la lista. Nos permite tener variables de distinto tipo (al declararla no
pondremos <Tipo> como en nuestro ejemplo)
Map: No almacena el orden en que se insertan los datos (algunas de sus implementaciones si lo hacen). Para almacenar los datos se hacen usando el par clavevalor. No
permite valores de clave repetidos pero si valores de valor repetidos. Nos permite tener variables de distinto tipo.
Set: No almacena el orden en que se insertan los datos (algunas de sus implementaciones si lo hacen). No permite valores duplicados. Nos permite tener variables de
distinto tipo. Es lo que debemos elegir si no queremos tener elementos repetidos en nuestra estructura de datos.
Lo primero que vemos en la línea 1 es que para trabajar con la clase ArrayList hay que importarla. Entre las líneas 7 y 13 tenemos un ejemplo de como trabajar con Arrays (ya lo
vimos con anterioridad). En la línea 14 nos encontramos con la creación de una variable llamada listadeStrings que es de tipo ArrayList y además le añadimos <String> lo cual
significa que en este ArrayList solo vamos a poder almacenar variables de tipo String. La primera diferencia con respecto a los Arrays es que aquí no definimos el tamaño del
ArrayList. Esto es porque los ArrayList, a diferencia de los Arrays, son dinámicos. Podemos variar su tamaño en tiempo de ejecución según nuestras necesidades. En la línea 16
vemos como añadir un elemento a nuestro ArrayList. En la línea 18 vemos que para obtener el tamaño de un ArrayList utilizamos el método size. Y en la línea 19 vemos que para
obtener una determinada posición de un ArrayList utilizamos el método get. Al igual que los en los Array, en los ArrayList se comienza a contar por 0. Hemos comentado
anteriormente que los ArrayList son dinámicos por lo que en el ejemplo anterior podríamos añadir un tercer elemento a la lista sin necesidad de crear otra variable nueva, sin
embargo, no podríamos hacerlo con el Array.
A continuación vamos a ver como quedaría el ejemplo anterior eliminando la parte relativa a los arrays y utilizando for mejorados para recorrer el ArrayList:
Lo relevante del código anterior lo encontramos en la línea 11 donde hacemos uso del método remove que nos permite borrar el elemento de la lista que nos interese. En la línea
12 y 17 nos encontramos con unos bucles for distintos a los que habíamos utilizado hasta la fecha. En estos bucles for lo que decimos es que extraiga cada vez el siguiente
elemento de la lista y lo guarde en una variable llamada elemento de tipo String.
Excepciones
Excepciones
En Java, las excepciones son una clase (documentación) que se lanza cuando ocurre un error en tiempo de ejecución. Es decir, no son errores de compilación de algo que
hemos escrito mal y el compilador no comprende sino que son errores que ocurren mientras nuestro programa está siendo usado. Java nos ofrece la posibilidad de controlar
estos errores y recuperarnos de ellos sin abortar la ejecución de nuestro programa.
Lo que vemos aquí es que el programa compila y se ejecuta sin mayor problema pero durante su ejecución se intenta realizar una división por 0 y se lanza una excepción
(ArithmeticException) con el error, nos indica en que línea de nuestro código ocurre (línea 7) y se detiene la ejecución del programa. En un entorno real no sería tolerable que
aunque una de las muchas cosas que pueden fallar el programa se detenga, por ello lo que hay que hacer es controlar la excepción y que el programa continúe su ejecución.
Vamos a ver como contener el error:
Lo que hacemos aquí es crear un bloque trycatchfinally. Dentro del try le decimos lo que queremos que haga y si hay algún error de tipo Exception lo capturamos y hacemos lo
que está dentro del catch. El bloque finally es opcional y es un trozo de código que se ejecutará siempre falle o no la ejecución en el bloque try. Todas las excepciones, como
ArithmeticException, derivan de Exception por eso si en un bloque catch capturamos Exception capturaremos cualquier excepción. Es muy cómodo capturar cualquier excepción
en un bloque catch pero lo idea es poner un bloque catch para cada excepción y así saber que falla concretamente. Vamos a ver un ejemplo:
En el código anterior aparecen 2 bloques catch, en el primero de ellos (línea 11) controlo las excepciones que pudiesen ocurrir de tipo aritmético y en el segundo bloque (línea 14)
capturo cualquier otro tipo de excepción.
En ocasiones puede resultarnos útil lanzar nosotros mismos un error bien de tiempo genérico (Exception) o bien extendiendo la clase Exception para crearnos nuestro error
personalizado. Dado que aún no hemos visto como extender una clase vamos a ver a continuación un trozo de código donde lancemos una excepción genérica:
En la imagen anterior vemos que creamos una función en la línea 6 que realiza la división de 2 parámetros. En la línea 7 comprobamos que el dividendo no sea 0 ya que no se
puede dividir por 0. En caso de que el dividendo sea 0 en la línea 8 lanzamos una excepción (realmente un objeto realmente que inicializamos con su constructor, veremos estos
conceptos en el siguiente módulo) con un mensaje personalizado. Como dentro de nuestra función lanzamos una excepción tenemos que indicar de algún modo que este
módulo lanza excepciones de tipo Excepcion, por ello en la línea 6 añadimos a nuestra función throws Exception. En el mail lo único que hago es mostrar por pantalla el resultado
de llamar a esta función. En el primer caso vemos que entra al catch (línea 15) mientras que en el segundo caso al no lanzarse ninguna excepción no se ejecuta el código
contenido en el catch. Ninguno de estos trycatch incluye el bloque finally que como dijimos anteriormente es opcional.
Convenios de escritura
Convenios de escritura
Cuando os hablé de "Constanes y variables" ya comenté algo sobre los convenios de escritura en Java. Vamos a recordarlo:
“ Si eres observador/a te habrás dado cuenta de que los tipos básicos empiezan en minúscula mientras que los objetos comienzan en mayúsculas. Es probable
que también te hayas percatado de que el nombre que asigno a las variables siempre comienza en minúsculas y el nombre que asigno a las constantes está
completamente en mayúsculas, esto son convenios de escritura del lenguaje Java y tu puedes seguir tu propio estilo de código pero es interesante hacer uso del
convenio porque facilita la lectura y comprensión del código yen caso de trabajar con otras personas se es mas productivo. En este módulo, un poco mas
adelante, hablaremos en mayor profundidad de esta cuestión.
Pablo Ruiz Soria Capítulo "Constantes y variables"
Hay que dejar claro que un convenio no es mas que eso, un convenio. No estamos obligados a seguirlo pero si va a facilitarnos la labor a la hora de entender código de otras
personas. Además, si acostumbramos a nuestro alumnado a seguirlo nos facilitará enormemente la tarea de corrección y detección de errores en su código. Voy a elaborar una
pequeña tabla donde recoger algunas generalidades al respecto:
Pregunta
Siempre el primer carácter en mayúsculas. Si son varias palabras, cada una de ellas separada por la primera
Clases Respuesta
mayúscula. Buscaremos nombres descriptivos pero no largos. Usaremos nombres en singular.
ClasificacionHistorica
pregunta
Siempre el primer carácter en minúsculas. Si son varias palabras, cada una de ellas separada por la primera
Variables respuesta
mayúscula. Buscaremos nombres descriptivos pero no largos. Usaremos nombres en singular.
clasificacionHistorica
PREGUNTA
Todo en mayúsculas. Si son varias palabras, cada una de ellas separada por guión bajo (_). Buscaremos nombres
Constantes RESPUESTA
descriptivos pero no largos. Usaremos nombres en singular.
CLASIFICACION_HISTORICA
En minúsculas. No es habitual que tengan varias palabras. Si son paquetes para web generalmente usan el dominio com.trivinet.modelo
Paquetes
invertido.
com.trivinet.util
obtenerPregunta(...)
Funciones y Siempre el primer caracter en minúsculas. Si son varias palabras, cada una de ellas separada por la primera
borrarRespuesta(...)
métodos mayúscula. Buscaremos nombres descriptivos pero no largos. Utilizaremos verbos.
establecerClasificacionHistorica(...)
a = b + c;
Operadores Estableceremos 1 espacio en blanco tras los mismos para facilitar la lectura.
a == b
Paréntesis dentro
Cuando un paréntesis no sea el último procuraremos dejar un espacio en blanco para facilitar la lectura. escribir( multiplicar(4, 5) );
de paréntesis
Bloques de código Todo el código dentro de un bloque (clase, método, condición, bucle, excepción,...) debe tener la misma identación
Longitud de las Evitaremos hacer líneas de longitud mayor a 80 caracteres (en Netbeans viene delimitado por una línea roja). Recordad
líneas que una sentencia, en Java, termina con un punto y coma, no con el fin de la línea.
No me cansaré de insistir en que el compilador no comprueba que sigamos ningún convenio (ni que la lógica del programa sea correcta). El compilador únicamente va a
comprobar que sintácticamente el código está escrito del modo adecuado.
Algoritmos y estructuras de resolución de problemas sencillos
Sería demasiado largo y farragoso comentar en este apartado todo el código de este proyecto no obstante he procurado que el código sea muy claro.
Para hacer más sencilla la lectura he dividido el código en 3 clases main. Para ejecutar una u otra basta con que en Netbeans, en las propiedades del proyecto, selecciones que
clase main quieres ejecutar en cada momento. También puedes colocarte encima de la clase que contenga main que quieras ejecutar y pulsando sobre ella con el click derecho
elegir run.
Tarea
Tu tarea una vez acabado el segundo módulo consiste en:
Crear un proyecto llamado Modulo2NombreApellido donde Nombre sea tu nombre y Apellido tu primer apellido. Ejemplo: Modulo2PabloRuiz
En el proyecto deberás crear una paquete llamado tarea.
Dentro del paquete tarea deberás crear una clase llamada Principal. En esta clase estará el método main.
La clase Principal deberá tener las funciones sumarEnteros, restarEnteros, multiplicarEnteros, dividirDecimales, calcularFactorial, sumarArray y sumarLista.
La función sumarEnteros deberá tener 2 parámetros que serán enteros y deberá mostrar una línea con el resultado de la operación.
La función restarEnteros deberá tener 2 parámetros que serán enteros y deberá devolver la resta del 2º parámetro al 1º.
La función dividirDecimales deberá tener 2 parámetros que serán decimales (double) y devolverá otro decimal (double). Si el divisor es igual a 0 lanzará una excepción
genérica con el mensaje "No se puede dividir por cero".
La función calcularFactorial deberá tener 1 parámetro entero y deberá devolver el factorial del parámetro dado. Puedes elegir entre hacerlo recursivo o no. En caso de que
el parámetro sea un número negativo se lanzará una excepción genérica con el mensaje "No puedo calcular el factorial de un número negativo"
La función sumarArray recibirá un parámetro, que será un vector de enteros. Deberá sumar todos los valores y devolver el resultado.
La función sumarLista recibirá un parámetro, que será una lista de tipo ArrayList que solo contendrá enteros. Deberá sumar todos y mostrar por pantalla el resultado.
En el main deberás controlar las excepciones que lancen los métodos para los que hemos establecido excepciones. La forma de controlarlos será mostrando por pantalla
el mensaje de la excepción y continuando ejecutando el resto de sentencias.
Obra publicada con Licencia Creative Commons Reconocimiento Compartir igual 4.0