Diego's weblog - Developer's notes

Todo | General | Design | Java

20070417 martes abril 17, 2007

Open Session In View, Spring & Hibernate

Estuve analizando las diferentes posibilidades que existen dentro del Spring Framework para la implementación del "pattern" Open session in view.

Spring propone dos formas:

Probe ambos mecanismos y encontre el primero tiene dos problema grave (al menos es lo que yo encontre)

Por ejemplo:

Grupo grupo = new Grupo();
grupo.setId(form.getIdGrupo());
empresa.setGrupo(grupo);


El objeto grupo queda en la session actual y si luego es consultado para ser mostrado en una tala por ejemplo, la descripcion seria null. Para resolver este problema hay que cargar el objeto grupo utilizando un load().

Grupo grupo = servicio.findById(form.getIdGrupo());   // cargo el objeto
empresa.setGrupo(grupo);

En el mecanismo de deferred session encontre que para ciertas consultas se pueden abrir una gran cantidad de sessiones, por lo que hay que tener en cuenta esto para definir el tamaño del pool de conexiones

( abr 17 2007, 04:47:34 PM ART ) Permalink Comentarios [0]

20070330 viernes marzo 30, 2007

OSCache y Tiles

En el proyecto que estoy trabajando actualmente existe cierto contenido que se genera dinamicamente que puede ser cacheado (por ejemplo en menu), para ello utilice oscache para cachear dicho contenido.
Pero tuve un problema a la hora de poner el tag <cache:cache> en mi layout.jsp (define el layout de mi pagina llamando a <tiles:insert>;).

Can't insert page '/layout.jsp' : Illegal to flush within a custom tag 

Ahora bien, hice la prueba rapida de poner el valor de flush en false y funciona:

<cache:cache>
  	<tiles:insert attribute="menu" flush="false"/>
</cache:cache>

Por otro lado lo que si funciona es utilizar el tag <cache:cache> dentro de las paginas jsp que tiles incluyo, por ejemplo en la pagina definida como body. En este caso si oscache realiza su trabajo correctamente y cache el contenido definido.

( mar 30 2007, 01:05:20 PM ART ) Permalink

20061219 martes diciembre 19, 2006

Tutorial de OT-Rules (Parte 2)

Segunda parte del tutorial que muestra como trabajar el engine de reglas OT-Rules.

http://opentranquera.sourceforge.net/tiki/tiki-read_article.php?articleId=5 ( dic 19 2006, 10:21:31 AM ART ) Permalink

20061124 viernes noviembre 24, 2006

OT-Web JSF Locator

Acabo de publicar en la wiki de OTF un articulo sobre como utilizar OT-Web JSF Locator para obtener e inyectar servicios (JNDI, Spring, EJB) a backing beans en un manera simlpe y flexible.

Link al articulo

( nov 24 2006, 11:27:52 AM ART ) Permalink

20061123 jueves noviembre 23, 2006

Tutorial de OT-Rules

Escribi un tutorial de una pequeña framework de rules que basicamente ayuda al programador Java a construir logica de negocio en pequeños fragmentos (clases) llamados rules que luego pueden ser compuestas y reutilizadas.
ot-rules

( nov 23 2006, 12:05:29 PM ART ) Permalink

20060317 viernes marzo 17, 2006

Invasión de POJOs

Ya hace un tiempo que los POJOs (Plain Old Java Objects) están invadiendo las diferentes capaz de nuestras aplicaciones. Empujados por el intenso uso de lightweight frameworks (Spring por ejemplo) y AOP (Aspect Oriented-Programming), este tipo de objetos se están utilizando masivamente en el desarrollo de nuevas aplicaciones en JEE (Java Enterprise Edition).

Los POJOs son utilizados en la capa de persistencia a través de los ORM, donde se realizan mapeos entre estos objetos y tablas del mundo relacional. Persistence frameworks como Hibernate, JDO o Java Persistence API alientan el uso de los pojos y suministran persistence transparente para estos objetos.

En la capa de servicios, cada ves es mas común ver pojos publicados bajo diferentes mecanismos (EJB, web services, etc) y gracias a la utilización de AOP se pueden obtener objetos con muy bajas dependencias que disfruten de servicios de bajo nivel como transacciones, seguridad, logging, validaciones, notificaciones, etc. Utilizando POJOs como facade simplifica el desarrollo permitiendo que toda la lógica sea desarrollada y testeada fuera del application server y al mismo tiempo soportar los servicios de bajo nivel ya mencionados.

En la capa de presentación se encuentra JSF, donde sus managed bean pueden verse como pojos, objetos sin dependencias que son manejados por JSF.

Ahora bien, en la capa de integración con otros sistemas, el jugador más importante es XML. Sin embargo hay formas de transformar XML a Pojo y viceversa utilizando frameworks como JAXB, XMLBeans o XStreams por mencionar algunas.

Donde también los POJOs entran en acción es en el desarrollo del modelo de dominio que representan las entidades del mundo real que el sistema trata de modelar. Aquí los POJOs suministran simplicidad, OOD (Object-Oriented Design), mantenibilidad y extensibilidad

Como dijimos anteriormente frameworks como Spring, Hibernate, etc. alientan el uso de POJOs para el desarrollo de aplicaciones y cabe destacar que EJB3 también alienta la utilización de POJOs sobre todo por nueva API de persistencia de Java - JPA y por el uso de POJOs Facade, donde el EJB Container es el encargado de suministrar los servicios de bajo nivel

Para concluir podemos decir que hoy en día, para desarrollar una aplicación lo que se desarrollaran son POJOs utilizando técnicas de OOP y OOD, conectándolos y configurándolos a través de frameworks externas como ser Spring, Hibernate, EJB3, etc.

( mar 17 2006, 04:20:23 PM ART ) Permalink Comentarios [1]

20060315 miércoles marzo 15, 2006

ADF (Awful Development Framework)

Hace un tiempo fui a un par de cursos de Oracle sobre ADF - Application Development Framework, aunque a mi me gusta llamarla "Awful Development Framework".
La verdad que no me gusta en nada (salvo la nueva versión que trae el diseño de paginas JSF bastante bueno) y aunque no la conozco profundamente voy a dar mi opinión acerca de esta mmm, llamemosla framework.

( mar 15 2006, 12:28:03 PM ART ) Permalink Comentarios [2]

20051115 martes noviembre 15, 2005

EJB3 Notes

La nueva especificación de EJB 3.0 tiene muchas variantes y mejoras con respecto a sus predecesoras:
- Simplifica el desarrollo de aplicaciones
- Uso del nuevo feature de J2SE 5, metadata, para especificar comportamiento esperado del container, para injectar recursos y servicios (otros beans) y especificar el mapeo objeto/relacional. De esta forma el bean provider puede obviar el deployment descriptor.
- Permite el uso de deployment descriptor para sobreescribir las configuraciones realizadas con anotaciones. Tambien se puede obviar el uso de anotaciones y utilizar solamente el deployment descriptor como mecanismo de configuración.
- Utiliza POJO/POJI para definir un Enterprise Bean Class. No hay dependencias con las viejas interfaces (EJBObject o EJBLocalObject).
- Uso mas flexible de excepciones (unchecked exceptions).
- Uso no obligado de callback methods aunque si es necesario si se desea recibir notificaciones y eventos del container. De echo los callback methods se pueden reemplazar por callback listeners de modo de no tener estos metodos dentro de la clase de negocio.
- Permite el uso de interceptores para session y message-driven bean.
- Se eliminaron las Home interface.
- Un entity bean es un objeto de dominio liviano.

( nov 15 2005, 10:30:59 AM ART ) Permalink Comentarios [0]

20051027 jueves octubre 27, 2005

Sun Certified Programmer for the Java 2 Platform, SE 5.0

Aca dejo un par de links de mocks para prepararse para esta certificación:
http://www.javabeat.net/javabeat/scjp5/index.php
http://www.examulator.com/phezam/login.php
http://www.wickedlysmart.com/SCJPStudyGuide/Java_5_SCJPquestions.html
http://www.richardchen.info/home/scjp/

Guía online:
http://java.boot.by/scjp-tiger/

Libros:
- Complete Java 2 Certification Study Guide, Fifth Edition
- Java 1.5 Tiger. A developer notebooks

( oct 27 2005, 11:33:30 AM ART ) Permalink Comentarios [0]

20051011 martes octubre 11, 2005

Java 5. ¿Que tiene de bueno y de malo?. Parte V

Varargs

Varargs (Variable Arguments) nos permite especificar que un método puede tomar múltiples argumentos de un mismo tipo, es decir, permite que pasar un número indeterminado de argumentos a un método. En versiones anteriores si queríamos hacer algo así tení­amos que pasar un array de objetos (Object[]) como argumento de un método, ahora con varargs queda más simple y claro el pasaje de parámetros indeterminado a un método, por ejemplo:

public void doIt(Object... args) {
 ...
}
 
this.doIt("Java", "5", "J2EE", new Integer(5));

Varargs se aplica teniendo en cuenta las siguientes reglas sintácticas y semánticas:
- El tipo de datos debe estar seguido de tres puntos (...)
      Type...
- El argumento variable debe ser el último en la lista de argumentos del método.
- Es interpretado como Type[]

De esta forma vemos que varargs lo que hace es ocultar el proceso de transformar el argumento variable en un Type[], creandolo con los parámetros pasados al método para luego invoca al método propiamente dicho pasándole el Type[].

Veamos otro ejemplo, ahora la forma de declarar el método main utilizando varargs se vería asi­:

public static void main(String... args) {
 ...
}

Una de las principales ventajas de varargs es que nos permite reducir el numero de métodos escritos para resolver una funcionalidad, en lugar de tener 4 o 5 métodos con diferentes listas de argumentos, podemos hacer uno solo con argumentos variables. Sin embargo el problema que surge con esto es que podemos llegar a tener un código que se preocupe mas por como trabajar con los argumentos variables que por la lógica de negocios que este debe resolver, por eso hay que tener cuidado y no abusar de este feature.
Otras de las ventajas es que se obtiene un código mas limpio y flexible.

Iterando sobre variable-length argument list

Ahora como hacer para trabajar con un argumento variable? Es muy simple, este es tratado como un array, por lo tanto se lo trabaja como si se estuviera trabajando un Type[].

public void doIt(String name, int ... codes) {
   StringBuilder sb = new StringBuilder("Name = ")
      .append(name)
      .append(" -> ");
   Formatter formatter = new Formatter(sb);
 
   for( int code : codes ) {
      formatter.format("%d ", code);
   }
 
   System.out.println( sb.toString() );
}

La llamada a este método se puede realizar de diferentes formas:

Test test = new Test();
test.doIt("jh");	// codes = new int[]{}
test.doIt("jh", 1);	// codes = new int[]{1}
test.doIt("jh", 1,2,3,4,5,6);	// codes = new int[]{1,2,3,4,5,6};

La salida del siguiente código es:

Name = jh -> 
Name = jh -> 1 
Name = jh -> 1 2 3 4 5 6 

Como se resuelve la sobrecarga y sobre escritura de métodos?

Unos de los temas a tener en cuenta cuando utilizamos varargs es la forma en la cual se resuelven la sobre carga y la sobre escritura de los métodos.
Por ejemplo que sucede si tenemos el siguiente código:

public class VargArgs {
 
   public static void main(String[] args) {
      VargArgs va = new VargArgs();
      va.doIt("a", "b", "c");
      va.doIt(1,2,3,4);
      va.doIt(1,2,"d");
      va.doIt("a", new Integer(10));
 
   }
 
   public void doIt(String... a) {
      System.out.println("String..." + Arrays.toString(a));
   }
 
   // Duplicate method.
   // public void doIt(String[] a) {
   //    System.out.println("[]" + Arrays.toString(a));
   // }
 
   public void doIt(Number... n) {
      System.out.println("Number..." + Arrays.toString(n));
   }
 
   public void doIt(Object... o) {
      System.out.println("Object..." + Arrays.toString(o));
   }
}

Como vemos tenemos varios métodos doIt sobrecargados con diferentes lista de argumentos, nada del otro mundo, pero que pasa si ejecutamos el método main de esta clase? Tendremos una salida como la que se muestra a continuación:

String...[a, b, c]
Number...[1, 2, 3, 4]
Object...[1, 2, d]
Object...[a, 10]

Bueno, creo que queda claro a que método se llama en cada lí­nea, pero ahora que sucede si realizamos algunos cambios en el código, como por ejemplo, declaramos un nuevo método doIt que reciba un String[]. Lo que sucede es que obtendremos un error en tiempo de compilación debido a que estaria el método duplicado. Otro cambio que hará que tengamos un error en tiempo de compilación en las lí­neas va.doIt(1,2,"d"); y va.doIt("a", new Integer(10)); al cambiar el signature del método public void doIt(Object... o) por public void doIt(Object[] o), pero porque? Es simple la declaración public void doIt(Object... o) significa que el método puede recibir una cantidad variable de argumentos mientras que public void doIt(Object[] o) significa que el método espera recibir un array de objetos.

Las reglas explicadas para la resolución de métodos explicadas en Java 5. ¿Que tiene de bueno y de malo?. Parte II son aplicadas a varargs.

En lo que respecta a la sobre escritura de métodos veámoslo con un ejemplo.

public class SubVarArgs extends VargArgs {
 
   public static void main(String[] args) {
      SubVarArgs s = new SubVarArgs();
      s.doIt(1,2,3,4);
      s.doIt(new Number[]{1,2,3});
   }
 
   public void doIt(Number... n) {
      System.out.println(this.getClass().getName() + "[]" + Arrays.toString(n));
   }
}

La salida es:

varargs.SubVarArgs[][1, 2, 3, 4]
varargs.SubVarArgs[][1, 2, 3]

Dado que se sobrescribe el método doIt(Number...) ambas llamadas se realizan sobre el objeto de la subclase. Ahora si cambiamos el signature de doIt(Number...) por doIt(Number[]) tendremos la siguiente salida:

Object[][1, 2, 3, 4]
varargs.SubVarArgs[][1, 2, 3]

Se invoca el método doIt(Object...) de la superclase dado que el compilador no entiende que se ha sobrescrito el método, si en cambio, se invoca doIt(Number[]) cuando llamamos el método pasándole un array de Number.
Otro detalle a tener en cuenta es que si cambiamos el signature doIt(Object...) de la superclase por el signature doIt(Object[]) nos dará un error de compilación debido a que no hay método que se resuelva para s.doIt(1,2,3,4).

Como podemos ver varargs es un interesante features de Tiger, pero deberí­a utilizarse con precaución y moderación y solamente cuando el beneficio sea alto. También deberí­a tenerse cuidado a sobrecargar y sobrescribir varargs methods. ( oct 11 2005, 03:49:12 PM ART ) Permalink Comentarios [1]

20050909 viernes septiembre 09, 2005

Java 5. ¿Que tiene de bueno y de malo?. Parte IV

For/in

Este feature me parece interesante dado que facilita/optimiza la forma sobre la cual iterar por una collection o array, el código es más simple dado que elimina el uso de un iterator o variables índices pero esto genera algunas limitaciones que explicare mas adelante.
Aqui un ejemplo de for/in:

Collection<String> list = new ArrayList<String>();   // Generic
list.add("for/in");
list.add("annotations");
list.add("autoboxing");
 
// Conventional for
for( Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
   String value = iter.next();;   // no-cast
   System.out.println( value );
}
 
// Enhanced for
for( String value : list ) {
   System.out.println( value );
}

Este nuevo for/in no nos da nada nuevo ya que se puede hacer lo mismo utilizando un for convensional. for/in puede hacer uso de Generics para de esta forma tambien evitar el casting, aunque esto no es un obligatorio.

Sintaxis.

for( Type identifier : Expression ) Statement

La expression debe ser un array o una instancia de la nueva interface java.lang.Iterable (java.util.Collection implementa java.lang.Iterable desde la version 5 de Java) que tiene el método public Iterator<T> iterator();. Esto permite crear clases que puedan ser iteradas utilizando el nuevo enhanced for. Type debe ser un tipo valida para Java (un objeto o un primitivo).
Basicamente lo que hace el for/in es traducirlo en un for convensional de la siguiente forma o siguiendo estos pasos:

for( Iterator iterator = Expression.iterator(); iterator.hasNext(); ) {
   Type identifier = (Type)iterator.next();
   Statement
}

A pesar de todo este feature tiene algunas consecuencias en su uso y por lo tanto genera limitaciones:
- No se puede modificar los valores de los elementos de un array de tipos primitivos.

int[] i = {1, 2, 3, 4, 5, 6};
for( int x : i ) {
   System.out.println(x);
   // No se modifica el valor del elemento en el array
   // aunque si se modifica dentro del bloque del for
   x++;
}

- No se puede eliminar elementos desde la collection, porque no se tiene el iterator.
- No se puede modificar la referencia de un objeto de la collecion dentro del loop, aunque se puede modificar el objeto en si mismo.

Collection list = new ArrayList();
list.add("for/in");
list.add("annotations");
list.add("autoboxing");
 
for( Object o : list ) {
   // Se modifica la referencia pero solo dentro del bloque for
   // No se modifica la collection
   o = new String("j2ee");
   System.out.println(o);
}

- No se puede utilizar para iterar simultaneamente varias collections o arrays en paralelo

( sep 09 2005, 10:40:03 AM ART ) Permalink Comentarios [1]

20050903 sábado septiembre 03, 2005

Java 5. ¿Que tiene de bueno y de malo?. Parte III

Continuando con la serie de notas sobre los features de Tiger, hoy voy a hablar de static imports.
Static imports permite importar miembros estáticos de clases o interfaces de forma tal de no hacer uso del antipattern "Constant Interface".
Static imports no me gusta. No me parece algo que brinde facilidades, sino todo lo contrario, creo que molesta y hace poco legible el código haciendo que este se vea mas como un conjunto de funciones en lugar declases con métodos. En el único caso en el que veo que static imports puede ser útil es al utilizar enums o constantes.

¿Trabajando con funciones?
Aquí daré unos ejemplos de como puede verse el código de una clase como si fueran funciones:

import static java.util.Arrays.sort;
import static java.lang.System.out;
 
public class StaticImportTest {
    public static void main(String... args) {
        sort(args);       // llamo a la función
        out.println( deepToString(args) );       // llamo a otra función
    }
}

Aquí vemos como una clase en Java se parece a un archivo de código en C. Los static imports actúan como la directiva include y la llamada al método sort parece como si estuviéramos llamando a una función. Por otro lado, además de parece código estructurado, el código pierde legibilidad. Imaginemos una clase con muchos métodos, también imaginemos que tenemos que modificar esa clase y nos encontramos con algo así en nuestro código.

public void execute() {
   Integer[] array = {5,8,2};
 
   sort(array);
   out.println( deepToString(array) );
}

Surgen las siguientes dudas: ¿El método sort es un método estático importado o es un método privado de la clase?. A primera vista no lo sabemos. ¿Que sucede si nosotros creamos un método para la clase llamado sort(Integer a[]) en un escenario como este?. Los métodos que realicen las llamadas al método estático sort de Arrays se verán modificados en su comportamiento dado que ahora llamarán al nuevo método private creado, con lo cual estamos introduciendo un error sin darnos cuenta. Esto es porque en runtime tratará primero de ejecutar métodos de la clase y luego los métodos estáticos importados.

public void execute() {
   Integer[] array = {5,8,2};
   sort(array);    // Llama al método de instancia sort y no Arrays.sort()
   out.println( deepToString(array) );
}
 
private void sort(Integer[] a) {
   // nothing
}

¿Que pasa si tenemos varios static imports que tienen los mismos métodos?. Bueno aquí el compilador se da cuenta que la llamada al método sort es ambigua y nos da un error.

import static java.lang.System.out;
import static java.util.Arrays.sort;
import static staticimport.array.MyArrays.sort;
 
public class StaticImportError {
 
   public static void main(String[] args) {
      int[] array = {5,8,2};
      sort(array);   // ERROR en tiempo de compilación
 
      for(int i: array) {
         out.println( i );
      }
   }
}
 
...
public class MyArrays {
   public static void sort(int[] a) {
      // nothing
   }
}

Como se puede ser en estos casos (al menos desde mi punto de vista) el código es confuso y poco claro. De hecho en puede leerse en http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html algo así:
Usar static import con moderación. Este es usado en situaciones cuando se necesita acceder con frecuencia a unos pocos objetos estáticos desde una o dos clases. El abuso de static import puede resultar en un código difícil de leer y mantener (como hemos visto ;)). Usado correctamente hace que el código sea más fácil de leer dada la eliminación de varios classnames repetidos. ( sep 03 2005, 10:14:42 AM ART ) Permalink Comentarios [0]

Java 5. ¿Que tiene de bueno y de malo?. Parte II

Otros de los problemas que puede acarrear el mal uso de autoboxing son:

Problema con el == y el equals
Este no es un problema en si, de echo el uso del metodo equals o de == no produce ningun problema en la ejecución de código java. Sino que el problema esta en que se puede producir una confusión y un uso incorrecto.
La confusión viene por el echo de que en el rango [-128, 127], la VM mantienen los wrapper como constantes cuando realiza autoboxing, es decir que:

Byte b1 = 10;
Byte b2 = 10;

Se cumple la condición (b1 == b2), pero si hacemos:

Byte b1 = new Byte((byte)10);
Byte b2 = new Byte((byte)10);

No se cumple que (b1 == b2) dado que al realizar el autoboxing del tipo primitivo 10 al objeto Byte se ejecuta el método estático valueOf(...) que verifica si el primitivo esta dentro del rango mencionado, si lo esta devuelve una wrapper constante, sino crea un nuevo objeto con el valor.

Veamos un ejemplo:

public static void testEquals(Number n1, Number n2) {
    if( n1 == n2 ) {      // comparacion de referencias de objetos, no hay auto-boxing
        System.out.println("Las referencias son iguales");
    }

    if( n1.equals(n2) ) {
        System.out.println("Tienen el mismo valor");
    }
}
public static void main(String[] args) {
        Integer i = 120;
        Integer b = 120;
        testEquals(i, b);
}

El resultado es el siguiente:
- Las referencias son iguales
- Tienen el mismo valor

Ahora si hacemos:

public static void main(String[] args) {
        Integer i = 129;
        Integer b = 129;
        testEquals(i, b);
}

El resultado es distinto ya que las dos referencias no apuntan a los mismos objetos Integer aunque tengan el mismo valor.
Por lo tanto es siempre recomendable utilizar el método equals al comparar wrappers

Problema con pasaje de parámetros a métodos sobrecargados.
Este problema lo mostrare con otro ejemplo. Supongamos tener la sigueinte clase:

public class Dummy {
    public void doIt(int x) {
        System.out.println("doIt(int x)");
    }
    public void doIt(Integer x) {
        System.out.println("doIt(Integer x)");
    }
    public void doIt(double x) {
        System.out.println("doIt(double x)");
    }
    public void doIt(Object x) {
        System.out.println("doIt(Object x)");
    }
    public static void main(String args...) {
        Dummy dummy = new Dummy();
        dummy.doIt(10);        
    }
}

Este código llama al metodo doIt(int x) y no hay ninguna duda de eso, pero que pasa ahora si este metodo no existe, a que metodo se llama?
Uno pensaria que se hace un autoboxing y se llama el método doIt(Integer x) dado que es el que corresponde por su tipo, pero no, se llama al metodo doIt(double x).
Porque pasa esto, bueno es por conpatibilidad con versiones anteriores a Tiger, por ejemplo, en java 1.4, al no existir autoboxing, las llamadas a los metodos se resolvian por compatibilidad de tipos. En este caso se llamaria a doIt(double x) y no a doIt(Integer x).
Ahora si tampoco existiera el metodo doIt(double x) si se realiza un autoboxing y se llama al metodo doIt(Integer x).
Por lo tanto podemos concluir con que la llamada a metodos se resuelve siguiendo el siguiente algoritmo:
1. El compilador intenta localizar el metodo sin utilizar boxing, unboxing o varargs.
2. Si el primer paso falla, el compilador intenta resolver el metodo permitiendo boxing y unboxing. varargs no es considerado.
3. Si el segundo paso fallo, el compilador intenta resolver el metodo una vez mas permitiendo boxing, unboxing y considerando los metodos con varargs.

Sin embargo el autoboxing es un feature que facilita mucho la programación en java y si es bien utilizado (y no se hace abuso de el) puede ser muy util a la hora de escribir codigo limpio y eficiente.
Una de las principales ventajas de autoboxing es en la utilización de collections, donde, junto al uso de generics, permite trabajar con tipos primitivos (agregar, sacar, etc) sin la necesidad de crear explicitamente objetos wrappers o realizar casteos de tipos, por ejemplo:

List<Long> longs = new LinkedList<Long>();
longs.add(12L);            // auto-boxing y luego coloca el objeto en la lista
longs.add(Long.MAX_VALUE);

Las coleciones no soportan tipos primitivos, pero con el uso de autoboxing pareciera que si. En realidad lo que aqui se hace es:

- Hacer autoboxing de 12 a un Long con el value = 12
- Poner en la lista longs el objeto wrapper creado.

Para obtener los valores desde la collection:

long lValue = longs.get(0);        //
Obtiene de la lista un objeto (Integer) y luego hace auto-unboxing
Long oValue = longs.get(1);

Lo que en realidad obtenemos de la lista (generics) es un objeto del tipo Long, y nuevamente con el uso de autoboxing, lo podemos trabajar como un tipo primitivo long sin realizar la llamada a los metodos del wrapper.
Como vemos aqui, no se escribio ningun casteo de tipos, esto es dado al uso de generic, que proximamente hablare de el.

( sep 03 2005, 10:12:46 AM ART ) Permalink Comentarios [1]

20050801 lunes agosto 01, 2005

Java 5. ¿Que tiene de bueno y de malo?. Parte I

A partir de la nueva versión de Java (Tiger) aparecieron nuevos features que prometen facilitar el proceso de desarrollo de aplicaciones en Java. Cada uno de nosotros puede estar de acuerdo o no, lo cierto es que a medida que se conozca más del tema y se adquiera experiencia en estos nuevos features, se va a poder decir con certeza cuáles de ellos fracasaron, cuáles pasaros desapercibidos y cuáles fueron un éxito.
Mientras tanto, voy a expresar desde este humilde weblog mi opinión acerca de las nuevas funcionalidades de Java 5, los que para mí son sus pro y contras, cuáles son los que van a dar que hablar y cuáles van a terminar complicando las cosas.

Para comenzar voy a dar una lista de dichas nuevas funcionalidades/facilidades que vienen en Java Standard Edition 5:

En esta ocasión, comenzaré hablando de auto-boxing/auto-unboxing.
Este features elimina la conversión manual de tipos primitivos a objetos wrapper permitiendo asignar a un objeto wrapper un tipo primitivo. Donde se puede ver claramente y a modo de ejemplo, el beneficio de esto es cuando trabajamos con Collections. Como todos sabemos las Collections trabajan únicamente con objetos por lo que para poder tener una colección de enteros debemos crear una colección de java.lang.Integer. Ahora con auto-boxing podemos guardar directamente el tipo primitivo, dejando que "alguien" se encargue de realizar la conversión.
Sin embargo hay que tener ciertos cuidados a la hora de trabajar con auto-boxing/auto-unboxing dado que su mal uso puede generar problemas.

Problema con creación de objetos
Tal vez sin saberlo estemos creando una gran cantidad de objetos innecesarios al trabajar intensamente con este features, por ejemplo veamos el siguiente código:

long start = System.currentTimeMillis();

int adder = 0;
int counter = 0;
for (int i = 0; i < 1000000; i++) {
	adder += i;
	counter++;
}

long end = System.currentTimeMillis();
System.out.printf("Tiempo consumido %f milisegundos", ((float)(end - start)));

Con este código simple y tonto podemos demostrar cómo se puede hacer un mal uso del autoboxing. Al ejecutarlo obtuve los siguientes resultados:
Tiempo promedio: 62 ms.
No hay garbage collection
No hay creación de objetos innecesarios
El método que más tarda es el printf(...)

Ahora si hacemos uso del autoboxing porque queremos que las variables adder y counter sean objetos Integer, podemos hacer lo siguiente:

long start = System.currentTimeMillis();
        
Integer adder = 0;
Integer counter = 0;
for (int i = 0; i < 1000000; i++) {
	adder += i; // auto-boxing. 
        counter++;  // auto-boxing. 
}
        
long end = System.currentTimeMillis();
System.out.printf("\nTiempo consumido %f milisegundos", ((float)(end - start)));

Al ejecutar este código obtuvimos unos resultados realmente aterradores:
Tiempo promedio: 10063 ms.
El garbage collector se ejecuta 3 veces
Hay picos de 61000 objetos java.lang.Integer creados
El método que mas tarda es el Integer.valueOf(...)

Como vemos la diferencia es importante, por lo que hay que tener cuidado cuando se trabaja con autoboxing.
Si lo que queremos es tener en dos objetos Integer los resultados, lo mejor sería hacer los cálculos con los tipos primitivos y luego crear sólo un objeto con el resultado.

En el próximo blog seguiré hablando de los problemas que ocasiona el autoboxing (el problema con el == y el "equals" y el problema con el pasaje de parámetros) y otros de los features de Java5, pero no crean que todas son pálidas, también hablare de las cosas buenas que brindan estos features y principalmente de los mejores features: Metadata y concurrent (según mi opinión).
( ago 01 2005, 02:38:22 PM ART ) Permalink Comentarios [3]