Home » 2012
Tuning Servidor de Apache Tomcat

Apache Tomcat
En mi trabajo hemos arrastrado un problema de de rendimiento del servidor de aplicaciones Apache-Tomcat, El que básicamente consiste en que si la maquina recibe muchas peticiones el contenedor web se pega y no es capas de resolver (En este caso solo nos queda reiniciar el contenedor).

1. Lo básico: versión de JVM, modo de ejecución y tamaño de heap de Java 

El contenedor web esta configurado con los siguientes parámetros para el catalina_opts /apache-tomcat-6,0,16/bin/catalina.sh

-Xms1024
-Xmx1024
-Xmn512
-XX:PermSize=128
-XX:MaxPermSize=512

2. Tuning del recolector de basura: hilos de ejecución

Por default, el número de hilos de ejecución asignados al GC son equivalentes al número de threads disponibles en el procesador. Sin embargo, esto puede ser muy ineficiente en sistemas con una buena cantidad de multithreading, siendo de 1/2 a 1 la proporción aconsejable.

-XX:ParallelGCThreads=6

3. Tuning del recolector de basura: incrementando la generación joven

Cuando se ejecuta un programa en Java, todos los objetos que se van creando pertenecen a tres generaciones, como se muestra en el siguiente esquema:

Las tres generaciones de objetos en Java. (Fuente: java.sun.com) Cuando se crea un objeto nuevo en Java con la instrucción new, éste inicialmente se encuentra en el espacio Edén (Eden space). Conforme se van ejecutando varios ciclos de recolección de basura o se van creando nuevos objetos, éstos van migrando a través de “espacios de supervivencia” (Survivor spaces) al ser copiados sobre áreas menos transaccionales de la memoria. La región tenured es la más importante pues en ésta se genera la mayoría de las operaciones en Java. Finalmente, aquellos objetos que han permanecido activos por mucho tiempo pasan a formar parte del espacio permanente (perm space) pues difícilmente serán eliminados.

Así entonces, en un ambiente altamente transaccional, es conveniente que entre el 6 y el 12% de la pila de memoria sea parte de la generación joven, pues se están creando muchos objetos en Java que serán migrados rápidamente. El tamaño por default es de apenas 2 MB y puede crecer de manera ilimitada, quemándose todo el espacio dedicado al tenured o perm, por lo que siempre es conveniente definir su tamaño explícitamente:
-XX:MaxNewSize=64m
-XX:NewSize=64m

4. Tuning del recolector de basura: corriendo en paralelo

Por default, el Garbage Collector de la máquina virtual de Java usa el modo “serial” de recolección, pero esto sólo sirve en máquinas con un solo CPU. Para servidores de aplicaciones con 2 o más cores, tenemos la dos opciones (modos) :

El Modo paralelo
-XX:+UseParallelGC

modalidad de “pequeños impulsos frecuentes”. Esta opción disminuye un poco el rendimiento del sistema a cambio de no congelar la aplicación cada que se llena el GC.

-XX:+UseConcMarkSweepGC
ó -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

5. Tuning del recolector de basura: incrementando la generación permanente

Así como estamos definiendo un tamaño para la generación joven, también es posible definir uno para el espacio permanente (perm space) que en aplicaciones con muchos objetos estáticos y utilerías (sobre todo en Ajax) pueden generar el temido java.lang.OutOfMemoryError: PermGen space. Cabe destacar que si estamos encontrando constantemente errores de este tipo aunque incrementemos el espacio considerablemente (>25% del espacio asignado al heap), significa que tenemos un problema de objetos no recolectados que requiere echarse un clavado en el código.

-XX:MaxPermSize=128m

6. Paginación de la memoria

El objetivo de la paginación en Java es optimizar los búferes de traducción y búsqueda en memoria (Translation-Lookaside Buffers – TLB). Estos son en pocas palabras, caches que almacenan los últimos mapeos de memoria virtual a física. Modificando los valores correspondientes se incrementa la eficiencia del uso memoria. En la mayoría de los casos no se recomienda pasar de 6 MB de paginación pues puede ser contraproducente.

-XX:+UseLargePages
-XX:LargePageSizeInBytes=5m

7. Non-Uniform Memory Architecture (NUMA)

Debido a que una buena parte de las arquitecturas multiprocesador están basadas en el uso de memoria de acuerdo a posiciones relativas a otro procesador o a través de memoria compartida entre procesadores, es posible utilizar una opción de “escopetazo” denominada NUMA. El uso de este parámetro en combinación con -XX:+UseParallelGC puede incrementar significativamente el desempeño:

-XX:+UseParallelGC
-XX:+UseNUMA

8. Tuning del recolector de basura: pasando de generación

en generación El parámetro -XX:SurvivorRatio puede utilizarse para ajustar el tamaño de los espacios de supervivencia. Aunque no es tan importante para el rendimiento, sí permite ayudarnos a definir cuál será el espacio para el resto de las generaciones, pues si son demasiado pequeños, los nuevos objetos serán copiados directamente en el espacio tenured y si son demasiado grandes, se está desperdiciando memoria. Por ejemplo, -XX:SurvivorRatio=6 significa que existirá una relación de 6 a 1 entre el Edén y los survivor spaces.

Por otro lado, la JVM define por defecto un “porcentaje de ocupación” del 50% del survivor space actual para empezar a copiar los objetos que contiene al siguiente espacio. Esto puede significar un desperdicio del 50% de la memoria designada a los survivor spaces, por lo que conviene incrementarla para hacer un uso más eficiente de la misma. -XX:TargetSurvivorRatio permite definir el porcentaje de uso necesario para copiar los objetos del actual espacio al siguiente:

-XX:SurvivorRatio=8
-XX:TargetSurvivorRatio=90

Clonar Objetos en Java

Clonar Objetos en Java
La clonación es el proceso de duplicación de un objeto para que en memoria existan dos objetos idénticos en el mismo instante de tiempo. Usualmente el objeto se clona directamente llamando al método:cualquierObjeto.cualquierMetodo(miObjetoImportante.clone());

Al igual que en muchos lenguajes orientados-a-objeto, en Java los objetos son pasados por referencia. Esto implica que cualquier acción tomada por el método “llamado” afectará el objeto que tiene el método “que llamó”, esto debido a que ambos objetos son el mismo.

La clase java.lang.Object contiene una implementación native y protected del métodoclone. Esta implementación (que depende de la máquina sobre la que se ejecute el código) determina cuanta memoria está siendo usada por el objeto a ser clonado, reserva la misma cantidad de memoria para el objeto clon, y copia los valores de memoria de la vieja dirección de memoria a la nueva. Y al final se devuelve un java.lang.Object el cual es la referencia al nuevo objeto (el clon).

Para implementar la clonación en una clase, se deben hacer dos cosas:
La clase debe implementar la interfaz Cloneable, esta interfaz no tiene métodos que implementar. El propósito de Cloneable es indicar al método clone dejava.lang.Object que el programador ha dado permiso explícito a la clase para permitir que los objetos instanciados a partir de ella sean clonados.
El método clone de la clase java.lang.Object debe ser sobrescrito con un acceso de tipo public en vez de protected. Es en este método que se implementará el código que clona del objeto.

La excepción CloneNotSupportedException es arrojada por el método clone de la clase java.lang.Object para prevenir que la operación de clonación se ejecute si no se ha otorgado el permiso para ello (es decir, se implemente la interfaz Cloneable).

En términos sencillos el método clone de la clase java.lang.Object crea un nuevo objeto mediante la copia exacta de los bytes de memoria y devolviendo una referencia, de esto se tiene que los objetos miembros de un clon apuntan a los mismos objetos que los objetos miembros del objeto original.

Cuando un objeto de la clase CloneTest es creado y a su atributo miembro se le asigna un valor, por ejemplo, “prueba”, la memoria de este objeto realmente solo contiene los bits que representan una referencia a un objeto String que contiene “prueba”. Cuando el métodoclone es ejecutado, el objeto es duplicado byte por byte y el clon contendrá una copia de la misma referencia que apunta al mismo objeto Stringque contiene “prueba”. El resultado final es que existe solamente una copia de “prueba” y que una llamada sobre el objeto o su clon para modificar su valor resultará en cambios para ambos. Esto es conocido como ‘shallow copy’, donde solamente los miembros primitivos (y referencias a objetos) del objeto que están completamente contenidos en la memoria del objeto son duplicados, pero el resto de los objetos miembros en el objeto no lo son.

Este enfoque no es suficientemente bueno para algunos casos, ya que en general los objetos no están compuestos solamente de tipos primitivos. String, Hashtable, Vector y otras clases que residen en el objeto a ser clonado, necesitan a su vez ser clonados, para que el proceso de clonación sea efectivo, esto es el que se conoce como clonación “profunda” (‘deep cloning’).

A pesar que la clonación puede ser necesaria, tambien existen situaciones (usualmente de seguridad) donde se desea prohibir la clonación de una clase, para esto existen varias alternativas, de las cuales las dos más importantes son:
Declarar la clase como final. Haciendo esto se previene que se puedan definir subclases para esta clase, e impedir que cualquiera pueda llamar al método clone desde dentro de la clase (usando el alcance protected). Si se usa esta alternativa para impedir la clonación se debe verificar que ninguna de las superclases se pueda clonar. En el caso que esto sea asi, se debe sobreescribir el método clone en la clase final y arrojar unaCloneNotSupportedException. A pesar que esta es la alternativa efectivamente impide la clonación, establece restricciones acerca de las capacidades de extender la clase, las cuales pueden no ser aceptable.
Implementar Cloneable y sobreescribir el método clone con un alcance public, y hacer que arroje una CloneNotSupportedException. A pesar que esto impide que la clase sea clonada, cualquier subclase puede hacer su propia implementación del métodoclone e implementar la clonación copiando los atributos uno por uno.

Existe otra forma (considerada como “oscura”) de clonar un objeto, que es la serialización (‘serializing’) del objeto. La serialización usa un método nativo externo al objeto, es similiar a la clonación en el sentido en que el estado binario del objeto es capturado desde memoria, pero en vez de copiarlo hacia otra dirección de memoria es copiado hacia un ‘stream’. En un futuro post pienso conversar un poco acerca de la serialización.

Ejemplo de Clonación en Java:

Clase Punto:

package clonico;

public class Punto implements Cloneable{
    private int x;
    private int y;
   public Punto(int x, int y) {
        this.x = x;
     this.y = y;
    }
    public Punto() {
        x=0;
        y=0;
    }
    public Object clone(){
        Object obj=null;
        try{
            obj=super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        return obj;
    }
    public void trasladar(int dx, int dy){
        x+=dx;
        y+=dy;
    }
    public String toString(){
        String texto="origen: ("+x+", "+y+")";
        return texto;
    }
}

Clase Rectángulo

package clonico;

public class Rectangulo implements Cloneable{
    private int ancho ;
    private int alto ;
    private Punto origen;

    public Rectangulo() {
     origen = new Punto(0, 0);
     ancho=0;
     alto=0;
    }
    public Rectangulo(Punto p) {
     this(p, 0, 0);
    }
    public Rectangulo(int w, int h) {
     this(new Punto(0, 0), w, h);
    }
    public Rectangulo(Punto p, int w, int h) {
     origen = p;
     ancho = w;
     alto = h;
    }
    public Object clone(){
        Rectangulo obj=null;
        try{
            obj=(Rectangulo)super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar");
        }
        obj.origen=(Punto)obj.origen.clone();
        return obj;
    }
    public void mover(int dx, int dy) {
     origen.trasladar(dx, dy);
    }
    public int area() {
     return ancho * alto;
    }
    public String toString(){
        String texto=origen+" ancho: "+ancho+" alto: "+alto;
        return texto;
    }
}

Ejecutar la clonación

package clonico;
public class ClonicoApp {
    public static void main(String[] args) {
        Punto punto=new Punto(20, 30);
        Punto pCopia=(Punto)punto.clone();
        System.out.println("punto "+ punto);
        System.out.println("copia "+ pCopia);

        Rectangulo rect=new Rectangulo(new Punto(0, 0), 4, 5);
        Rectangulo rCopia=(Rectangulo)rect.clone();
        System.out.println("rectángulo "+ rect);
        System.out.println("copia "+ rCopia);

        try  {
//espera la pulsación de una tecla y luego RETORNO
            System.in.read();
        }catch (Exception e) {  }
    }
}

JavaMail utilizando TLS

JavaMail utilizando TLS
1. JavaMailutilizando TLS

Ejemplo de enviar correo con JavaMail utilizando TLS.
package com.mkyong.common;
 
import java.util.Properties;
 
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
 public class SendMailTLS {
 
 public static void main(String[] args) {
   final String username = "user@gmail.com";
  final String password = "pass";
   Properties props = new Properties();
  props.put("mail.smtp.auth", "true");
  props.put("mail.smtp.starttls.enable", "true");
  props.put("mail.smtp.host", "smtp.gmail.com");
  props.put("mail.smtp.port", "587");
   Session session = Session.getInstance(props,
    new javax.mail.Authenticator() {
  protected PasswordAuthentication getPasswordAuthentication() {
   return new PasswordAuthentication(username, password);
   }
    });
   try {
   Message message = new MimeMessage(session);
  message.setFrom(new InternetAddress("from@gmail.com"));
  message.setRecipients(Message.RecipientType.TO,
    InternetAddress.parse("to@gmail.com"));
  message.setSubject("Subject");
  message.setText("email de prueba");
    Transport.send(message);
    System.out.println("Finalizado");
   } catch (MessagingException e) {
   throw new RuntimeException(e);
  }
 }
}

Diagramas de caso de uso (Use Case)

Diagramas de caso de uso (Use Case)

Casos de Uso (Use Case)

Introducción
El diagrama de casos de uso representa la forma en como un Cliente (Actor) opera con el sistema en desarrollo, además de la forma, tipo y orden en como los elementos interactuan (operaciones o casos de uso).
Un diagrama de casos de uso consta de los siguientes elementos:
  • Actor.
  • Casos de Uso.
  • Relaciones de Uso, Herencia y Comunicación.
Elementos
  • Actor:

    Una definición previa, es que un Actor es un rol que un usuario juega con respecto al sistema. Es importante destacar el uso de la palabra rol, pues con esto se especifica que un Actor no necesariamente representa a una persona en particular, sino más bien la labor que realiza frente al sistema.
    Como ejemplo a la definición anterior, tenemos el caso de un sistema de ventas en que el rol de Vendedor con respecto al sistema puede ser realizado por un Vendedor o bien por el Jefe de Local.
  • Caso de Uso:

    Es una operación/tarea específica que se realiza tras una orden de algún agente externo, sea desde una petición de un actor o bien desde la invocación desde otro caso de uso.
  • Relaciones:
    • Asociación 
      Es el tipo de relación más básica que indica la invocación desde un actor o caso de uso a otra operación (caso de uso). Dicha relación se denota con una flecha simple.
    • Dependencia o Instanciación 
      Es una forma muy particular de relación entre clases, en la cual una clase depende de otra, es decir, se instancia (se crea). Dicha relación se denota con una flecha punteada.
    • Generalización 
      Este tipo de relación es uno de los más utilizados, cumple una doble función dependiendo de su estereotipo, que puede ser de Uso (<>) o de Herencia (<>).
      Este tipo de relación esta orientado exclusivamente para casos de uso (y no para actores).
      extends: Se recomienda utilizar cuando un caso de uso es similar a otro (características).
      uses: Se recomienda utilizar cuando se tiene un conjunto de características que son similares en más de un caso de uso y no se desea mantener copiada la descripción de la característica.
      De lo anterior cabe mencionar que tiene el mismo paradigma en diseño y modelamiento de clases, en donde esta la duda clásica de usar o heredar.
Ejemplo:
Como ejemplo esta el caso de una Máquina Recicladora:
Sistema que controla una máquina de reciclamiento de botellas, tarros y jabas. El sistema debe controlar y/o aceptar:
  • Registrar el número de ítemes ingresados.
  • Imprimir un recibo cuando el usuario lo solicita:
    1. Describe lo depositado
    2. El valor de cada item
    3. Total
  • El usuario/cliente presiona el botón de comienzo
  • Existe un operador que desea saber lo siguiente:
    1. Cuantos ítemes han sido retornados en el día.
    2. Al final de cada día el operador solicita un resumen de todo lo depositado en el día.
  • El operador debe además poder cambiar:
    1. Información asociada a ítemes.
    2. Dar una alarma en el caso de que:
      1. Item se atora.
      2. No hay más papel.
Como una primera aproximación identificamos a los actores que interactuan con el sistema:
Luego, tenemos que un Cliente puede Depositar Itemes y un Operador puede cambiar la información de un Item o bien puede Imprimir un informe:
Además podemos notar que un item puede ser una Botella, un Tarro o una Jaba.
Otro aspecto es la impresión de comprobantes, que puede ser realizada después de depositar algún item por un cliente o bien puede ser realizada a petición de un operador.
Entonces, el diseño completo del diagrama Use Case es:

Formatear una fecha y Obtener un String

Formatear una fecha y Obtener un String
Algo que siempre nos da mucho problema es el trabajo con fechas en java, hoy me encontré con un problema, les dejo la solución que encontré para que la tomen en cuenta si se topan con lo mismo. Se trata de formatear una fecha de forma simple para poder mostrar simplemente el texto mediante programación en java, eliminando la complejidad de los objetos GregorianCalendar o Date, mediante la clase SimpleDateFormat

Ejemplo:
    SimpleDateFormat sdf = new SimpleDateFormat("dd - MM - yyyy");
    Calendar cal = Calendar.getInstance(); // hoy
    System.out.println("Hoy es " + sdf.format(cal.getTime()));

La clase SimpleDateFormat es muy sencilla de utilizar en java. Simplemente al constructor hay que pasarle cómo se deben formatear las fechas. dd es el día, MM es el mes y yyyy es el año. Se puede ver una lista de los posibles valores que admite en la API de SimpleDateFormat.

Una vez inicializada la clase, el método format devuelve un StringBuffer con la fecha debidamente formateada. Se le debe pasar un objeto de tipo Date, que se puede extraer del GregorianCalendar mediante el método getTime()…y ya está este sencilla rutina de programación en java.

Como implementar la Herencia en Java

Como implementar la Herencia en Java

HERENCIA EN JAVA

La herencia es parte integral de Java (y de todos los lenguajes de programación orientados a objetos). Los usuarios de Java siempre utilizan herencia cuando crean sus clases, porque implícitamente cuando se crea cualquier clase en Java, esta hereda de la clase Object.
La Herencia es el mecanismo por el que se crean nuevos objetos definidos en términos de objetos ya existentes. Por ejemplo, si se tiene la clase Ave, se puede crear la subclase Pato, que es una especialización de Ave.
            class Ave {
        String color;
        }
           class Pato extends Ave {
        int numero_de_patas;
        }


La palabra reservada extends se usa para generar una subclase (especialización) de un objeto. Una Pato es una subclase de Ave. Cualquier cosa que contenga la definición de Ave será copiada a la clase Pato, además, en Pato se pueden definir sus propios métodos y variables de instancia. Se dice que Pato deriva o hereda de Ave.
La herencia sirve para la reutilización de código, otro ejemplo de esto es la clase Automóvil en la cual se pueden definir los métodos más comunes como lo son acelerar, frenar y transportar, sin embargo si se necesita una clase Patrulla que también es un tipo de Automóvil, si no existiera la herencia, entonces se tendrían que definir los métodos acelerar, frenar, transportar y además los métodos particulares de patrulla que serían prender sirena y apagar sirena, en ese sentido el programador estaría trabajando de más, pero como existe la herencia, esto conlleva a la facilidad de aprovechar los métodos ya definidos en Automóvil y poderlos utilizar en la clase Patrulla.
La representación con código del ejemplo anterior es:
class Automovil{
        public void acelerar(){
           System.out.println("el automovil está acelerando");
           }
        public void frenar(){
           System.out.println("el automovil está frenando");
           }
       public void transportar(){
           System.out.println("el automovil está tarnsportando");
           }
    }
class Patrulla extends Automovil{
       public void prenderSirena(){
           System.out.println("Sirena encendida");
           }
       public void apagarSirena(){
           System.out.println("Sirena Apagada");
           }
    }

Control de excepciones en la programación en Java

Control de excepciones

GESTIÓN DE EXCEPCIONES Y ERRORES
A. Introducción

El control de flujo en un programa Java puede hacerse mediante las ya conocidas sentencias estructuradas (if, while, return). Pero Java va mucho más allá, mediante una técnica de programación denominada gestión de excepciones.
Mediante las excepciones se podrá evitar repetir continuamente código, en busca de un posible error, y avisar a otros objetos de una condición anormal de ejecución durante un programa.
Durante este capítulo estudiaremos la gestión de excepciones y errores, sin pretender profundizar demasiado, pero sí fijando la base conceptual de lo que este modo de programación supone.
Mediante la gestión de excepciones se prescindirá de sentencias de control de errores del tipo:
if ( error == true )

  return ERROR;


B. Tipos de excepciones
Existen varios tipos fundamentales de excepciones:
  • Error: Excepciones que indican problemas muy graves, que suelen ser no recuperables y no deben casi nunca ser capturadas.

  • Exception: Excepciones no definitivas, pero que se detectan fuera del tiempo de ejecución.

  • RuntimeException: Excepciones que se dan durante la ejecución del programa.

Todas las excepciones tienen como clase base la clase Throwable, que está incluida en el paquete java.lang, y sus métodos son:
  • Trowable( String mensaje ); Constructor. La cadena es opcional

  • Throwable fillInStackTrace(); Llena la pila de traza de ejecución.

  • String getLocalizedMessage(); Crea una descripción local de este objeto.

  • String getMessage(); Devuelve la cadena de error del objeto.

  • void printStackTrace( PrintStream_o_PrintWriter s ); Imprime este objeto y su traza en el flujo del parámetro s, o en la salida estándar (por defecto).

  • String toString; Devuelve una breve descripción del objeto.
C. Funcionamientoa.) Introducción
Para que el sistema de gestión de excepciones funcione, se ha de trabajar en dos partes de los programas:
  • Definir qué partes de los programas crean una excepción y bajo qué condiciones. Para ello se utilizan las palabras reservadas throw y throws.

  • Comprobar en ciertas partes de los programas si una excepción se ha producido, y actuar en consecuencia. Para ello se utilizan las palabras reservadas try, catch y finally.
b.) Manejo de excepciones: try - catch - finally
Cuando el programador va a ejecutar un trozo de código que pueda provocar una excepción (por ejemplo, una lectura en un fichero), debe incluir este fragmento de código dentro de un bloque try:
try {

  // Código posiblemente problemático

}


Pero lo importante es cómo controlar qué hacer con la posible excepción que se cree. Para ello se utilizan las clausulas catch, en las que se especifica que acción realizar:
try {

  // Código posiblemente problemático

} catch( tipo_de_excepcion e) {

  // Código para solucionar la excepción e

} catch( tipo_de_excepcion_mas_general e) {

  // Código para solucionar la excepción e

}


En el ejemplo se observa que se pueden anidar sentencias catch, pero conviene hacerlo indicando en último lugar las excepciones más generales (es decir, que se encuentren más arriba en el árbol de herencia de excepciones), porque el intérprete Java ejecutará aquel bloque de código catch cuyo parámetro sea del tipo de una excepción lanzada.
Si por ejemplo se intentase capturar primero una excepción Throwable, nunca llegaríamos a gestionar una excepción Runtime, puesto que cualquier clase hija de Runtime es también hija de Throwable, por herencia.
Si no se ha lanzado ninguna excepción el código continúa sin ejecutar ninguna sentencia catch.
Pero, ¿y si quiero realizar una acción común a todas las opciones?. Para insertar fragmentos de código que se ejecuten tras la gestión de las excepciones. Este código se ejecutará tanto si se ha tratado una excepción (catch) como sino. Este tipo de código se inserta en una sentencia finally, que será ejecutada tras el bloque try o catch:

try {

} catch( Exception e ) {

} finally {

  // Se ejecutara tras try o catch

}


c.) Lanzamiento de excepciones: throw - throws
Muchas veces el programador dentro de un determinado método deberá comprobar si alguna condición de excepción se cumple, y si es así lanzarla. Para ello se utilizan las palabras reservadas throw y throws.
Por una parte la excepción se lanza mediante la sentencia throw:
if ( condicion_de_excepcion == true )

  throw new miExcepcion();


Se puede observar que hemos creado un objeto de la clase miExcepcion, puesto que las excepciones son objetos y por tanto deberán ser instanciadas antes de ser lanzadas.
Aquellos métodos que pueden lanzar excepciones, deben cuáles son esas excepciones en su declaración. Para ello se utiliza la sentencia throws:
tipo_devuelto miMetodoLanzador() throws miExcep1, miExcep2 {

  // Codigo capaz de lanzar excepciones miExcep1 y miExcep2

}


Se puede observar que cuando se pueden lanzar en el método más de una excepción se deben indicar en su declaración separadas por comas.
d.) Ejemplo de gestión de excepciones
Ahora que ya sabemos cómo funciona este sistema, conviene ver al menos un pequeño ejemplo, que ilustre al lector en el uso de las excepciones:
// Creo una excepción personalizada

class MiExcepcion extends Exception {

  MiExcepcion(){

    super(); // constructor por defecto de Exception

  }

  MiExcepcion( String cadena ){

    super( cadena ); // constructor param. de Exception

  }

}


// Esta clase lanzará la excepción

class Lanzadora {

  void lanzaSiNegativo( int param ) throws MiExcepcion {

    if ( param < 0 )

      throw new MiExcepcion( "Numero negativo" );

  }

}


class Excepciones {

  public static void main( String[] args ) {

    // Para leer un fichero

    Lanzadora lanza = new Lanzadora();

    FileInputStream entrada = null;

    int leo;

    try {

      entrada = new FileInputStream( "fich.txt" );

      while ( ( leo = entrada.read() ) != -1 )

        lanza.lanzaSiNegativo( leo );

      entrada.close();

      System.out.println( "Todo fue bien" );

    } catch ( MiExcepcion e ){ // Personalizada

      System.out.println( "Excepcion: " + e.getMessage() );

    } catch ( IOException e ){ // Estándar

      System.out.println( "Excepcion: " + e.getMessage() );

    } finally {

      if ( entrada != null )

        try {

          entrada.close(); // Siempre queda cerrado

        } catch ( Exception e ) {

        System.out.println( "Excepcion: " + e.getMessage() );

        }

      System.out.println( "Fichero cerrado." );

    }

  }

}


class Excepciones {

  public static void main( String[] args ) {

    // Para leer un fichero

    FileInputStream entrada = null;

    Lanzadora lanza = new Lanzadora();

    int leo;

    try {

      entrada = new FileInputStream("fich.txt");

      while ( ( leo = entrada.read() ) != -1 )

        lanza.lanzaSiNegativo( leo );

      System.out.println( "Todo fue bien" );

    } catch ( MiExcepcion e ){ // Personalizada

      System.out.println( "Excepcion: " + e.getMessage() );

    } catch ( IOException e ){ // Estándar

      System.out.println( "Excepcion: " + e.getMessage() );

    } finally {

      entrada.close(); // Así el fichero siempre queda cerrado

      System.out.println( "Fichero cerrado" );

    }

  }

}


Este programa lee un fichero (fichero.txt), y lee su contenido en forma de números.
Si alguno de los números leídos es negativo, lanza una excepción MiExcepcion, Además gestiona la excepción IOException, que es una excepción de las que Java incluye y que se lanza si hay algún problema en una operación de entrada/salida.
Ambas excepciones son gestionadas, imprimiendo su contenido (cadena de error) por pantalla.
La salida de este programa, suponiendo un número negativo sería:
Excepcion: Numero negativo
Fichero cerrado

En el caso de que no hubiera ningún número negativo sería:
Todo fue bien
Fichero cerrado

En el caso de que se produjese un error de E/S, al leer el primer número, sería:
Excepcion: java.io.IOException
Fichero cerrado

Errores comunes en programación en Java

Errores comunes en programación en Java

  • Una Clase no está en el directorio correcto
    Este error de sintaxis ocurre si el comando javac no puede encontrar un archivo .java en el directorio esperado. Si una Clase está en el paquete por defecto (no tiene la declaración del package en la primera línea), entonces esta Clase pertenece al directorio actual de trabajo o al directorio donde apunta el flag sourcepath del javac. Si una Clase está a un paquete, entonces pertenece a un subdirectorio debajo del directorio actual de trabajo o a un subdirectorio debajo del directorio donde apunta el flan sourcepath del javac. Por ejemplo, si existe una Clase llamada com.hello.HelloWorld entonces su nombre es HelloWorld y su paquete es com.hello. Si el flan sourcepath está configurada a c:src, entonces el archivo HelloWorld.java debe estar ubicado en el subdirectorio: c:srccomhello.
  • El nombre de la Clase pública no coincide con el nombre del archivo
    Cada archivo .java puede contener sólo una Clase pública. El nombre de esa Clase pública debe coincidir exactamente con el nombre del archivo antes de la extensión .java, respetando incluso las mayúsculas y minúsculas. Por ejemplo, una Clase pública llamada MyClass debe estar en un archivo MyClass.java y no en myclass.java. Este es un error de sintaxis.

  • Error en mayúsculas y minúsculas. Java es un lenguaje case sensitive, esto es que debemos respetar las mayúsculas y minúsculas. (miVar no es igual a mivar). Si hacemos referencia a un identificador que no está bien escrito entonces obtendremos un error de sintaxis.

    • Usando equals contra la asignacion
    • En Java este error puede ser incluso un error de lógica o sintaxis. Para comparar 2 referencias para igualarlas se usa el operador == (el operador de igualdad). Para asignar el valor de la derecha a la variable de la izquierda se usa el operador = (operador de asignación). Los programadores novatos a veces escriben: if (miValor = valorEsperado) Este código intenta evaluar el valor Esperado como un valor booleano en lugar de intentar la evaluación de igualdad entre mi Valor y valorEsperado. Si valorEsperado es del tipo booleano, entonces el código tendrá un error de lógica y probará si el valor Esperado es verdadero o falso. Si valorEsperado no es del tipo booleano, entonces el código lanzará un error de compilación debido a que la estructura if requiere un valor booleano que sea retornado de la comparación (miValor = valorEsperado), pero en Java el operador = siempre retorna el valor de la derecha.
  • Olvidar que los índices en Java empiezan en 0.
    Los índices de los arreglos de Java y las listas empiezan en 0, myArray[0], o myList.get(0). Asegurarse que su loop for no cause errores por este motivo. Si hacemos más loops de los que son posibles, entonces obtendremos el error: ArrayIndexOutBounds exception. Si hacemos menos loops de los requeridos, entonces tendremos un error de lógica.

  • NullPointerException
    El NullPointerException, la maldición de los programadores en Java. Los NullPointerExceptions son errores de lógica causados cuando un programa intenta acceder a métodos o atributos en una referencia que está nula. Si nuestro objeto no ha sido inicializado o ha sido establecido a null con el operador =, entonces la llamada el método o el acceso a uno de sus atributos no es válido.

Ejemplo de Sockets en Java

Ejemplo de Sockets en Java
En este ejemplo se presenta la programación Java A toma de corriente. El servidor espera una conexión. Cuando se establece una conexión de un cliente. El cliente puede enviar los datos. En el ejemplo actual, el cliente envía el mensaje "Hola, mi servidor". Jue terminar la conexión, el cliente envía el mensaje de "adiós". A continuación, el servidor envía el mensaje de "adiós" también. Finalmente se termina la conexión y el servidor espera una conexión a otro. Los dos programas regentado debe estar en la misma máquina. Sin embargo, si usted quiere ejecutarlos en dos máquinas diferentes, usted puede simplemente cambiar la dirección "localhost" por la dirección IP de la máquina donde se ejecute el servidor.



Server
import java.io.*;
import java.net.*;
public class Provider{
 ServerSocket providerSocket;
 Socket connection = null;
 ObjectOutputStream out;
 ObjectInputStream in;
 String message;
 Provider(){}
 void run()
 {
  try{
   //1. creating a server socket
   providerSocket = new ServerSocket(2004, 10);
   //2. Wait for connection
   System.out.println("Waiting for connection");
   connection = providerSocket.accept();
   System.out.println("Connection received from " + connection.getInetAddress().getHostName());
   //3. get Input and Output streams
   out = new ObjectOutputStream(connection.getOutputStream());
   out.flush();
   in = new ObjectInputStream(connection.getInputStream());
   sendMessage("Connection successful");
   //4. The two parts communicate via the input and output streams
   do{
    try{
     message = (String)in.readObject();
     System.out.println("client>" + message);
     if (message.equals("bye"))
      sendMessage("bye");
    }
    catch(ClassNotFoundException classnot){
     System.err.println("Data received in unknown format");
    }
   }while(!message.equals("bye"));
  }
  catch(IOException ioException){
   ioException.printStackTrace();
  }
  finally{
   //4: Closing connection
   try{
    in.close();
    out.close();
    providerSocket.close();
   }
   catch(IOException ioException){
    ioException.printStackTrace();
   }
  }
 }
 void sendMessage(String msg)
 {
  try{
   out.writeObject(msg);
   out.flush();
   System.out.println("server>" + msg);
  }
  catch(IOException ioException){
   ioException.printStackTrace();
  }
 }
 public static void main(String args[])
 {
  Provider server = new Provider();
  while(true){
   server.run();
  }
 }
}
  
Client
  import java.io.*;
import java.net.*;
public class Requester{
 Socket requestSocket;
 ObjectOutputStream out;
  ObjectInputStream in;
  String message;
 Requester(){}
 void run()
 {
  try{
   //1. creating a socket to connect to the server
   requestSocket = new Socket("localhost", 2004);
   System.out.println("Connected to localhost in port 2004");
   //2. get Input and Output streams
   out = new ObjectOutputStream(requestSocket.getOutputStream());
   out.flush();
   in = new ObjectInputStream(requestSocket.getInputStream());
   //3: Communicating with the server
   do{
    try{
     message = (String)in.readObject();
     System.out.println("server>" + message);
     sendMessage("Hi my server");
     message = "bye";
     sendMessage(message);
    }
    catch(ClassNotFoundException classNot){
     System.err.println("data received in unknown format");
    }
   }while(!message.equals("bye"));
  }
  catch(UnknownHostException unknownHost){
   System.err.println("You are trying to connect to an unknown host!");
  }
  catch(IOException ioException){
   ioException.printStackTrace();
  }
  finally{
   //4: Closing connection
   try{
    in.close();
    out.close();
    requestSocket.close();
   }
   catch(IOException ioException){
    ioException.printStackTrace();
   }
  }
 }
 void sendMessage(String msg)
 {
  try{
   out.writeObject(msg);
   out.flush();
   System.out.println("client>" + msg);
  }
  catch(IOException ioException){
   ioException.printStackTrace();
  }
 }
 public static void main(String args[])
 {
  Requester client = new Requester();
  client.run();
 }
}
  

Entradas populares