RSS

Archivo de la categoría: Estudio

Las clases de cadena: String, StringBuffer y StringBuilder

Java proporciona tres clases diferentes para tratar con cadenas de caracteres:

Los objetos String son cadenas de caracteres estáticas, al crearse e inicializarse no pueden cambiar su valor. Es porque son inmutables que pueden ser compartidas por varias referencias.

Los objetos StringBuffer y StringBuilder, por el contrario, son cadenas de caracteres dinámicas, pueden cambiar su contenido y su capacidad.

La diferencia entre los objetos StringBuffer y StringBuilder es que los primeros pueden ser utilizados de forma segura por varios hilos, siendo sus métodos sincronizados mientras que los objetos StringBuilder no.

La clase StringBuilder se añadió en la versión J2SE 1.5.

Read the rest of this entry »

Anuncios
 
5 comentarios

Publicado por en 27 marzo, 2012 en Tema 6

 

Etiquetas: , , , , , , , , , ,

Assertions: Habilitacion Selectiva, Usos Apropiados

Sobre versiones:

En el examen siempre estaremos usando la versión 6 del compilador (javac) y la versión 6 del lanzador (java). Si existen preguntas sobre código de versiones anteriores siempre serán en el contexto de compilar y ejecutar código antiguo con la versión 6 de Java.

A partir de la versión J2SE 1.4 assert es una palabra clave.
En versiones anteriores assert podía ser utilizada como identificador al no existir todavía las assertions.

Si quisiéramos compilar código antiguo en el que assert se utiliza como identificador hemos de indicar la versión al compilar con la opción -source:

javac -source 1.3 Assert_Identificador.java

Compilaría ok, aunque con warnings, indicando que assert se utiliza como identificador y ejecutaría ok.

Si ese código antiguo lo compiláramos con la versión 1.4 o con la versión por defecto, 1.6, nos daría error:

javac -source 1.4 Assert_Identificador.java
javac Assert_Identificador.java
javac -source 1.6 Assert_Identificador.java
javac -source 6 Assert_Identificador.java

De la misma forma, si un código que utiliza assert como palabra clave se compilara indicando la versión antigua en la que existía como identificador, también se produciría un error de compilación:

javac -source 1.3 Assert_PalabraClave.java


Habilitación e Inhabilitación selectiva:

En la entrada anterior vimos en un ejemplo cómo habilitabamos las assertions en tiempo de ejecución para un fichero .class en concreto:

java -ea Triangulo

Sin embargo, la habilitación o deshabilitación se puede hacer también:

  • Para todas las clases:
    java -ea           //habilita assertions.
    java -da           //deshabilita assertions.
    java -ea -dsa    //habilita assertions en todas las clases menos las clases de sistema.
  • Para todas las clases de un paquete y sus subpaquetes:
    java -ea: proyecto.utiles… //habilita clases del paquete proyecto.utiles y subpaquetes.
    java -da: proyecto.utiles… //deshabilita clases del paquete y subpaquetes.
  • Usando combinaciones:
    java -ea -da: proyecto.utiles.Calendario //Habilita assertions menos la clase Calendario
    java -da -ea: proyecto.utiles… //Deshabilita assertions menos las clases del paquete y
    //subpaquetes


Usos Inapropiados: 

  • Comprobar argumentos de método público.
    Al ser públicos y poder ser utilizados por terceros se debe garantizar con un control más estricto que las assertions, ya que si las assertions están deshabilitadas no se produce ninguna comprobación. Si los valores de los argumentos de un método público son incorrectos se debe lanzar una excepción.
  • Comprobar argumentos de línea de comandos.
    De la misma forma si los valores pasados como argumentos a un programa se necesitan validar no deben ser comprobados con assertions sino con excepciones.
  • Provocar efectos colaterales.
    Las assertions no deberían provocar cambios en el estado del programa. No deben modificarse datos dependiendo de si están habilitadas o no.


Usos Apropiados: 

  • Comprobar argumentos de método privado.
    Los métodos privados serán llamados desde algún código público en el que ya se haya garantizado la correción de los argumentos pasados. Por lo tanto sí se pueden realizar suposiciones con assertions dentro del código privado.
  • Comprobar casos que nunca se producirán (incluso en métodos públicos).
    En bloques if o switch para verificar que ciertas ramas o casos no se deben alcanzar nunca se coloca un assert(false) para que si estamos equivocados en nuestra suposición falle.

En el siguiente post veremos algunos ejercicios y preguntas sobre assertions.

 
Deja un comentario

Publicado por en 20 marzo, 2012 en Tema 5

 

Etiquetas: , , , , ,

Assertions: Introducción y Ejemplo

Una aserción es una expresión lógica que el programador supone que siempre será verdadera cuando se ejecute. Es una forma de confirmar que esta suposición es cierta durante el desarrollo y así evitar tener que programar código que compruebe o controle casos que no se producirán.

Tenemos dos formas de utilizar las assertions:

assert(expresion_logica);
assert(expresion_logica): expresion_valor;

La segunda sintaxis nos permite además establecer una expresión que nos dará más información sobre el error. Esta expresion_valor será cualquier expresión que pueda ser convertida a String, es decir puede ser un valor primitivo, una cadena, un objeto, una función que devuelva alguna de las anteriores, etcétera.

Características:

  • Se incorporaron en la versión J2SE 1.4
  • Siempre se afirma que algo será verdadero.
  • Las assertions están deshabilitadas por defecto.
  • Para habilitar las assertions añadir al comando java el parámetro -ea (ó -enable assertions).
  • Para deshabilitar las assertions añadir al comando java el parámetro -da (ó -disableassertions).
  • La clase java.lang.AssertionError desciende de java.lang.Error y ésta a su vez de java.lang.Throwable.

Ejemplo:
En este programa vamos a construir una clase Triangulo. Tendremos un constructor con los lados como parámetros. En la función esRectangulo que devuelve true si el triángulo es rectángulo y false en caso contrario, colocamos una aserción sobre los lados del triángulo.

import java.lang.Math;
public class Triangulo {

    private float ladoa;
    private float ladob;
    private float ladoc;

    public Triangulo(float ladoa, float ladob, float ladoc){
        this.ladoa = ladoa;
        this.ladob = ladob;
        this.ladoc = ladoc;
    }

    public boolean esRectangulo(){
        //Sabemos un lado de un triangulo debe ser menor que la suma
        //de los otros dos lados.
        assert(ladoa < ladob + ladoc): "\nladoa: " + ladoa
                                     + " no es < que:  "
                                     + ladob + " + " + ladoc;
        return(Math.pow(ladoc,2) == Math.pow(ladoa,2) + Math.pow(ladob,2));
    }

    public static void main (String[] args){
        //Triangulo con valores de lados correctos.
        Triangulo t1 = new Triangulo(6,8,10)
        If t1.esRectangulo(){
            System.out.println("El triangulo t1 es rectangulo");
        }
        //Creamos un triangulo cuyos lados harán saltar la assertion.
        Triangulo t2 = new Triangulo(10,3,2);
        if t2.esRectangulo(){
           System.out.println("El triangulo t2 es rectangulo");
        }
    }
}

Resultado:
Vemos en la captura que primero hemos compilado el fichero fuente.
En segundo lugar, hemos ejecutado el programa, pero al estar deshabilitadas las assertion por defecto no ocurre ningún error.
Por último ejecutamos el programa habilitando las assertions y vemos que la condición no se cumple al comprobar los lados del segundo triángulo.
Nos añade a la traza del error la cadena “ladoa: 10.0 no es < que: 3.0 + 2.0”

 
Deja un comentario

Publicado por en 17 marzo, 2012 en Tema 5

 

Etiquetas: , , , , ,

Control del Flujo: Excepciones

Excepción

Es un evento excepcional que altera el flujo normal del programa. Cuando esto ocurre decimos que se ha lanzado una excepción.

Una excepción se puede generar:

  • en la JVM, como respuesta a una condición inesperada (Caso 1).
  • en el código, lanzadas explícitamente por el programador utilizando la sentencia throw (Caso 2).

Las excepciones del primer caso se llaman no comprobadas (unchecked) y las del segundo comprobadas (checked).

Ejemplo Caso 1: No comprobadas.
Por ejemplo, al intentar acceder a una posición inválida en un array.

public class PruebaOutOfBounds {
    public static void main (String[] args){
        int[] notas = new int[5];
        for (int i = 0; i<=5; i++){
            notas[i] = i*2;
            System.out.println("notas["+i+"]=" + notas[i]);
        }
    }
}

Otras excepciones no comprobadas son: ArithmeticException, ClassCastException, NullPointerException, …
En general son aquellas que descienden de la clase RuntimeException.


Ejemplo Caso 2: Comprobadas.

Cuando lanzamos explícitamente una excepción.

...
 public void reverse() throws Exception{
    if (nombre == null){
       throw new Exception ("El nombre es nulo.\n Lanzamos excepcion al intentar hacer
                             reverse().");
    }
    else
    {
        for (int i = nombre.length()-1; i >=0; i --)
            System.out.println(nombre.charAt(i));
    }
}
...

En general son aquellas que descienden de la clase Exception, excluyendo RuntimeException.


Regla del Manejo o la Declaración
Las excepciones comprobadas que un método pueda lanzar se deben declarar.

Si se produce una excepción comprobada en el código, el método debe:

  • manejar la excepción utilizando el bloque try-catch-finally
  • ó declarar la excepción y pasar la responsabilidad de declaración o gestión al método llamante.

Para declarar la excepción se utiliza la sentencia throws.

Manejando Excepciones
El manejo de excepciones en Java se lleva a cabo principalmente mediante las sentencias: try, catch y finally.

try{
.... //Código que puede provocar una excepcion
}
catch (Excepcion1){   //Puede haber 0, 1 o muchos bloques catch.
       //En caso de haber 0 debe existir bloque finally.
....
}
finally{  //Puede haber 0 o 1 bloque finally.
....   //En caso de haber 0 debe existir bloque catch.
}

En el bloque try encerramos el código que puede lanzar una excepción.
En el bloque catch definimos qué excepción y con qué código tratarla.
En el bloque finally escribimos código que siempre se ejecuta se produzca o no la excepción.

Ejemplo:

public class Alumno{
//...
   public static void main (String[] args){
        try{
         Alumno a = new Alumno("Ana", 12, 6);
         System.out.println(a);
         a.reverse();

         Alumno c = new Alumno();
         System.out.println(c);
         c.reverse();

       }
       catch (Exception e) {
           System.out.println("--> Hemos capturado la excepcion!!.");
       }
       finally {
           System.out.println("--> Siempre se ejecuta se produzca o no excepcion.");
       }
  }
}

Restricciones de los bloques try-catch-finally:

  • Un bloque try debe tener un bloque catch o un bloque finally asociado.
  • Entre un bloque try y catch no puede escribirse código.
  • Si hay varios bloques catch las excepciones más específicas deben colocarse antes que las más generales.
 
2 comentarios

Publicado por en 10 enero, 2012 en Estudio, Tema 5

 

Control del Flujo: Bucles II (break, continue, etiquetas)

Una vez que hemos visto los bucles en Java vamos a ver cómo les afectan las siguientes sentencias: break y continue.

Escribimos un bucle anidado y vemos la diferencia entre break y continue:

public class BucleConBreak{
    public static void main(String[] args){
        for (int i = 0; i< 6; i++){
            for (int j=0; j<5; j++){
                if (j==3){
                    break;
                }
                else{
                    System.out.println("iteracion [i,j]: " + i + ", " + j);
                }
            }
        }
    }
}

El resultado es:

La sentencia break hace que se salga completamente del bucle más interno y proseguimos con la siguiente iteración del bucle externo.

El mismo código pero con continue:

public class BucleConContinue{
     public static void main(String[] args){
         for (int i = 0; i< 6; i++){
             for (int j=0; j<5; j++){
                 if (j==3){
                     continue;
                 }
                 else{
                      System.out.println("iteracion [i,j]: " + i + ", " + j);
                 }
             }
         }
      }
 }

Devuelve:

La sentencia continue hace que pasemos a la siguiente iteración del bucle más interno.

Etiquetas

Es común utilizar las etiquetas con bucles for o while y en conjunción con las sentencias break y continue.

Una etiqueta se coloca antes de la sentencia a etiquetar seguida de ‘:’
Son útiles cuando tenemos bucles anidados y queremos especificar en cuál de ellos queremos hacer un break o continue.

En el siguiente ejemplo tenemos un ejemplo de break etiquetado:
El funcionamiento normal del break sería salir del bucle más interno, el while en este caso.
Sin embargo, el break etiquetado hace que rompa el bucle etiquetado, es decir el for.

public class BucleBreakLabeled{
    public static void main (String[] args){
        boolean esVerdadero = true;
        externo: //etiqueta la siguiente sentencia, es decir el for.
        for (int i = 0; i<5; i++){
            while (esVerdadero){
                System.out.println("Hola!");
                break externo; //break con etiqueta, hace que rompa la sentencia de la etiqueta, el for.
            }
            System.out.println("Despues del while!");
        }
        System.out.println("Despues del for!");
    }
}

Devuelve:

Las sentencias break y continue con etiquetas deben estar dentro de un bucle con la misma etiqueta, si no dará error de compilación.

 
5 comentarios

Publicado por en 8 diciembre, 2011 en Estudio, Tema 5

 

Etiquetas: , , , , , ,

Control del Flujo: Bucles

Los bucles nos permiten alterar el flujo de ejecución de un programa ejecutando repetidamente una sentecia o grupo de sentencias.

En Java 6 tenemos tres opciones distintas a la hora de realizar iteraciones:

  • while,
  • do while,
  • for (normal y mejorado)

Vamos a ver cada una de ellas en detalle.


While

Es el bucle indicado cuando no se sabe de antemano cuántas veces se va a ejecutar el bucle. Simplemente queremos que se repitan ciertas acciones mientras la condición del bucle sea cierta.

//inicialización de variables
while (condicion){   //La condicion debe evaluarse a boolean
    //codigo         //Puede no ejecutarse ninguna vez
}

Cómo funciona:

Al entrar en el while se comprueba la condicion por primera vez.
Si resulta falsa no llega a ejecutar el código y se prosigue la ejecución fuera del bucle.
Si es cierta se ejecuta el código y se vuelve a comprobar la condición.
Así sucesivamente hasta que la condición devuelva falso y salgamos del bucle.

Como veremos la última sentencia que se ejecutará en un bucle siempre será la comprobación de la condición.

Por ejemplo:
En este código la variable i vuelve a incrementarse en la última comprobación de la condición del bucle, cuando ésta ya es falsa.

public class EjemWhile1{
    public static void main (String[] args){
        int i = -1;
        boolean encontrado = false;
        int[] medidas = {10, 30, 40, 50, 70};
        while (++i < 5 && !encontrado){
            if(medidas[i] == 40){
             encontrado = true;
            }
        }
        System.out.println(i);
    }
}

En los bucles while estar atento a:

  • Declaración de variables en la condición del while. No se puede, deben estar declaradas con anterioridad.
  • Expresiones en la condición del while que no sean boolean.
    Por ejemplo: enteros en lugar de boolean o asignaciones en lugar de comparaciones, darán error de compilación.


Do While

En estos bucles primero se ejecuta el código y luego se comprueba la condición, por lo que tenemos asegurado que el código se ejecuta al menos una vez.

do{
    elem = pila.obtener();
    System.out.println("elem: " + elem);
} while (!pila.esVacia());

Cómo funciona:
En primer lugar se ejecuta el código del bucle.
A continuación se comprueba la condición. Si esta es falsa se prosigue la ejecución fuera del bucle. Si es verdadera se ejecuta el código y se vuelve a comprobar la condición.

Estar atento a las mismas consideraciones que en el while.


For

Es el bucle que solemos utilizar cuando sabemos cuántas veces queremos ejecutar cierto código.

En su sintaxis podemos destacar tres partes importantes:
– declaración e inicialización de variables
– condición
– incremento.

Aunque ninguna de ellas son obligatorias.

Ejemplo de bucle mínimo for:

for ( ; ; ){ //sin inicializacion, condición ni incremento. Sería un bucle infinito.
    //infinito
}

Ejemplo de un bucle for que equivaldría a un while:(sin inicialización ni incremento)

int i = 0;
for ( ; i<10 ; ){
    i++;
}

Ejemplo de un bucle for típico:

for (int i=0;i<10;i++){
    //declaración e inicializacion "int i=0"
    //condicion "i<10"
    //incremento "i++"
    System.out.println("i: " + i);
}

Cómo funciona:

La inicialización de la variable se ejecuta al principio una sola vez.
A continuación se comprueba la condición y si es falsa se prosigue la ejecución fuera del bucle.
Si resulta cierta se ejecuta el código, se incrementa la variable y se vuelve a comprobar la condición.

Consideraciones del For.

Declaración e inicialización:

  • Se pueden declarar 0, 1 o más variables del mismo tipo. Si hay más de una se separan por comas.
  • Las variables declaradas en el for pierden su ámbito al salir del bucle for.
  • Esta parte sólo se ejecuta una vez, al principio de la ejecución del bucle.

Condición:

  • Sólo se puede comprobar una condición no varias.

Incremento:

  • Se ejecuta despúes de que se ejecute el código del for.


For “Mejorado”

Simplifica recorrer un array o una colección. Tiene dos partes, la declaración y el elemento a recorrer.

int[] array = {10,20,30,50};
for (int elem: array){
    System.out.println("elem: " + elem);
}

En la declaración: hay que declarar una variable compatible con el tipo de los elementos del array o de la colección.

En la expresión: será una variable array, colección o un método que las retorne.

 
Deja un comentario

Publicado por en 30 noviembre, 2011 en Estudio, Tema 5

 

Etiquetas: , , , , , , , ,

Control del Flujo: If y Switch

Las sentencias condicionales permiten ejecutar código de forma selectiva.
En Java tenemos las sentencias condicionales if y switch.

Sentencia If:
La sintaxis más sencilla de una sentencia if es:

if (expresionLogica)  //Si expresionLogica se evalúa a true entonces se ejecuta codigo.
   codigo

Si se tiene una sola sentencia de código no es obligatorio encerrarla entre llaves pero siempre es recomendable por legibilidad.

Ejemplo:

if (precio < 100){
    comprar();  //Mas legible entre llaves.
}

 

Si nos encontramos un if sin llaves debemos recordar que solo aplica a la primera sentencia.

if (precio < 100)
    comprar();      //Solo esta sentencia forma parte del if.
    salirTienda();  //No forma parte del código del if. Siempre se ejecuta.
    volverACasa();  //No forma parte del código del if. Siempre se ejecuta.

La cláusula else es opcional. Se incluye cuando queremos que se ejecute código en el caso de que no se cumpla la condición en el if.

if (precio < 100){
    comprar();
}
else{
    System.out.println("Yo no soy tonto.");
}

También podemos tener una estructura if, else-if, else. Se da en los casos en los que queremos comprobar varias condiciones.

if (precio < 100){
    comprar();
}
else if (price < 2000 && tengoCredito){
    comprarConTarjeta();
}
else{
    System.out.println("Yo no soy tonto.");
}

En las sentencias If se cumplirá:

  • Habrá 0 o muchos else-if y precederán a la cláusula else.
  • Habrá 0 o 1 else e irá a continuación de todas las cláusulas else-if.
  • Cuando una condición se cumple el resto no se comprueba.
  • Si tenemos un else y no sabemos a que if corresponde será el más cercano sin else.
  • La asignación en una condición no da error si se trata de un lógico: if(indicador=true)


Switch

Con esta sentencia vamos a evaluar una expresión y dependiendo de su valor ejecutaremos un código u otro:

switch (expresion){
    case constante1: codigo1
    case constante2: codigo2
    case constante3: codigo3
    default: codigo
}

Si expresion coincide con alguna de las constantes se ejecutará el código de ese case y se seguirá ejecutando el código de los siguientes case hacia abajo hasta que se encuentre una sentencia break.

La sentencia default es opcional y se puede especificar cuando queremos que se ejecute un código para cualquier valor que sea distinto a los especificados en los case.

En los siguientes ejemplos podemos comprobar cómo afecta al resultado la existencia y posición de las sentencias breaks y default:

1. Ejemplo de un Switch Típico.
Switch con breaks en cada case y una clásula default al final.
Recorremos el array niveles. Cada valor entra en su case correspondiente y para al tener la sentencia break. Al estar la cláusula default al final no hace falta que tenga break.

public class EjemploSwitch1{
    public static void main (String[] args){
        int[] niveles = {1, 2, 3, 0};

        System.out.println("\nEjecucion Switch Tipico (breaks y default al final): " );
    	for (int i=0; i < niveles.length; i++){  	{
            System.out.println("Nivel: " + niveles[i]);
    	    switch (niveles[i]){
            case 1:   System.out.println("\tNivel Basico.");
                      break;

            case 2:   System.out.println("\tNivel Intermedio.");
                      break;

            case 3:   System.out.println("\tNivel Avanzado.");
                      break;

            default: System.out.println("\tNivel no informado.");
            }
    	}
    }
}

Resultado:


2. Sentencia Default No al Final.
En este caso hemos colocado la sentencia default sin break después del primer case. Todos los case tienen break. Cuando niveles[i] es igual a 0, ejecuta el código asociado a default. Al no tener break pasa al case 2, ejecuta su código y entonces sí para al tener break.

public class EjemploSwitch2{
    public static void main (String[] args){
        int[] niveles = {1, 2, 3, 0};
	System.out.println("\nEjecucion Switch con Breaks Default enmedio sin break: " );
    	for (int i=0; i < niveles.length; i++)   	{
            System.out.println("Nivel: " + niveles[i]);
    	    switch (niveles[i]){
            case 1:   System.out.println("\tNivel Basico.");
                      break;

            default:  System.out.println("\tNivel no informado.");

            case 2:   System.out.println("\tNivel Intermedio.");
                      break;

            case 3:   System.out.println("\tNivel Avanzado.");
                      break;

            }
    	}
    }
}

Ejecución:


3. Sentencias Case sin Break (Ejemplo en el que no tiene lógica aplicarlo).
En este Switch comprobamos qué ocurre si no colocamos ningún break. Para cada valor de niveles se ejecutan todos los case y default.

public class EjemploSwitch3{
    public static void main (String[] args){
        int[] niveles = {1, 2, 3, 0};
        System.out.println("\nEjecucion Switch sin Breaks (entra en todos los case cada vez): ");
        for (int i=0; i < niveles.length; i++)
        {
            System.out.println("Nivel: " + niveles[i]);
    	    switch (niveles[i])
            {
              case 1: System.out.println("\tNivel Basico.");

              case 2: System.out.println("\tNivel Intermedio.");

              case 3: System.out.println("\tNivel Avanzado.");

              default: System.out.println("\tNivel no informado.");
            }
        }
    }
}

Ejecución:


4. Sentencias Case Sin Break (Ejemplo en el que sí podría ser útil).
En este caso comprobamos cómo a veces puede tener lógica para nuestro código dejar los case sin break. Hemos cambiado el orden de las constantes en los case.

public class EjemploSwitch4{
    public static void main (String[] args){
        int[] niveles = {1, 2, 3, 0};

	System.out.println("\nEjecucion Switch sin Breaks (con logica que podria ser correcta): ");
        for (int i=0; i < niveles.length; i++)
        {
            System.out.println("Nivel: " + niveles[i]);
    	    switch (niveles[i])
            {
              case 3: System.out.println("\tNivel Avanzado.");

              case 2: System.out.println("\tNivel Intermedio.");

              case 1: System.out.println("\tNivel Basico.");
                      break;

              default: System.out.println("\tNivel no informado.");
            }
    	}
    }
}

Ejecución:


En el switch se debe cumplir:

  • La expresión evaluará a char, byte, short, int o enum.
  • Las constantes deben ser constantes en tiempo de compilación.
  • Hay que usar break cuando se necesite parar evitar la ejecución de los case posteriores.
  • La cláusula default no tiene por qué ser la última.
  • No puede haber dos case comprobando el mismo valor. No compilará.
  • No se pueden omitir las cláusulas case ni los ‘:’
 
Deja un comentario

Publicado por en 28 noviembre, 2011 en Estudio, Tema 5

 

Etiquetas: , , , , , , ,

 
A %d blogueros les gusta esto: