blog de ezamudio

Cómo leer registros de base de datos como un Stream de Java

He estado usando Spring desde la versión 1.0 y una de las clases que siempre me han resultado extremadamente útiles es JdbcTemplate. Esperaba que para la versión 5 integrara funcionalidad del API de stream de Java, pero no fue así.

Sin embargo a veces necesito realizar búsquedas en base de datos que devuelven miles o incluso millones de registros, y no puedo usar los métodos de JdbcTemplate que devuelven listas porque me quedo sin memoria. Los métodos que usan RowCallbackHandler son más apropiados, pero sería mucho más conveniente poder usar Streams de Java, particularmente si se pueden leer los resultados como objetos usando algún RowMapper.

Así que decidí hacer mi propio generados de Stream para usar con un JdbcTemplate. Al final, terminé con uno que es realmente más genérico y se puede usar con cualquier código que genere elementos ya sea de manera finita o infinita (aunque para streams infinitos existe una API mucho más simple). No es suficiente material como para generar una biblioteca, así que decidí publicarlo como un post.

Odio las excepciones verificadas

De verdad que deberían haber eliminado por completo las excepciones verificadas para Java 8. Estorban. No es una coincidencia que casi todos los demás lenguajes de la JVM las eliminaron.

BEGIN RANT

Tengo una clase donde implemento un método abstracto más o menos así:

 

Kotlin, parte 3: Métodos de extensión y sobrecarga de operadores

Kotlin permite la sobrecarga de operadores, como Scala y C++, pero de manera controlada, como Groovy. Es decir, no se pueden definir operadores de manera arbitraria como en Scala, donde se puede definir un método  , pero sí se pueden tener métodos que se puedan invocar con operadores como   etc.

Es curioso que siendo un lenguaje con tipado estático, no se fueron por el camino "limpio" para implementar esto, que era definir interfaces para los operadores (por ejemplo, Summable, o Plus, Minus, etc), sino que lo implementaron de igual manera que en Groovy, sólo que pues en Groovy funciona porque es un lenguaje dinámico. Esto presenta dos problemas: primero, que hay que saberse muy bien cuáles son los operadores que se pueden sobreescribir, junto con los nombres de los métodos correspondientes, los cuales no siempre son obvios a la hora de estar implementado uno (Para usar   ¿es divided, quotient, div o qué?) y el otro, que es más difícil saber si una clase tiene operadores sobrecargados o no, ya que hay que revisar los métodos que implementa, en vez de simplemente revisar las interfaces que implementa, y honestamente es más fácil simplemente hacer prueba y error (a ver si funciona si le pongo un  ).

Kotlin, parte 2: (not so) typesafe null y otras monerías

Una característica importante de Kotlin es que maneja seguridad en nulos. Esto es algo que varios lenguajes han estado implementando últimamente, porque ahorra muchos dolores de cabeza.

Normalmente, una variable de cualquier tipo que sea objeto, acepta  . En Kotlin no es así; para que una variable acepte null, se necesita especificar de esa forma. Esto no compila:

 

Porque   ha sido definida como de tipo  , y no acepta nulos. Para que acepte nulos, se tiene que definir así:

 

Los tipos opcionales se pueden usar en parámetros de funciones, tipos de retorno y declaraciones locales.

Cuando se tiene un valor que puede ser null, no se puede usar de manera directa. Hay que verificar que el objeto exista; esto se puede lograr de varias formas:

 

Kotlin: El nuevo lenguaje del emperador (1 de 3)

Hace unas semanas, Google anunció con bombo y platillo que ya soportan oficialmente Kotlin en Android. Para mucha gente, esta fue la primera vez que escucharon algo acerca del lenguaje y, como era de esperarse, a partir de ese momento han salido supuestos expertos en Kotlin hasta debajo de las piedras, ofreciendo seminarios y cursos y demás.

Yo llevo unos años siguiéndole la pista a Kotlin medio de lejos, por mi trabajo en Ceylon; así que creo que es un buen momento para contarles mi opinión al respecto. No les voy a decir si deben usar Kotlin o no; escribo esto porque estoy seguro que muchos lo van a probar y probablemente lo empiecen a usar en proyectos reales, pero tal vez por razones muy simples como la sintaxis o que si no tiene punto y coma o, simplemente, porque no es Java (esta es la razón más popular por la que recibió tan cálida bienvenida en el mundo de Android).

Spring Batch, más allá del tutorial

Parte de la operación de un sistema en el que llevo ya años trabajando, consiste en generar varios reportes diarios para conciliar con proveedores. El proceso es automatizado y ya hay componentes reutilizables para realizar esto, pero la cantidad de productos últimamente ha crecido bastante y esto trae un problema de desempeño, pues cada reporte lee la misma tabla, pero con criterios diferentes, para obtener prácticamente el mismo tipo de datos: Las ventas de X producto de un día.

La tabla en cuestión contiene las ventas de todos los productos, de modo que lo que ocurre diariamente es que se realiza la misma consulta, una vez por producto; algo así como   y solamente cambia el producto. Si tenemos 20 productos, pues son 20 consultas a la tabla.

Comunicación asíncrona entre procesos Java

En este post de jpaul estuve comentando acerca de algunas de las broncas de RMI, y de cómo hay opciones más eficientes para cuando se necesita implementar comunicación eficiente entre dos aplicaciones Java, usando algo similar a RMI.

Primero que nada, quiero mostrar cuál es el problema concreto con RMI: cada llamada que se recibe en la aplicación que publica el componente, se hace en un hilo separado. Para demostrar esto, tomé el ejemplo original y lo modifiqué un poco: El servidor tarda un poco de tiempo, y también imprime el nombre del hilo actual y el número total de hilos activos:

 

Varianza en Ceylon

Bueno pues después del artículo maratónico acerca de varianza en Java, ahora quiero explicar cómo se implementó esto en Ceylon. Para ello vamos a usar los mismos ejemplos, de modo que quede clara la comparación.

Lo primero son las tres clases para el ejemplo, y la primera función:

 

Hasta aquí, todo funciona exactamente igual que en Java:

 

En Ceylon también existe la covarianza en los tipos de retorno, similar a lo que se introdujo en Java 5:

 

Con los parámetros no se puede hacer algo similar. Ceylon no tiene sobrecarga de métodos, pero no tiene contravarianza en los parámetros; por lo tanto, al refinar un método de un supertipo, los parámetros deben ser exactamente del mismo tipo que en la declaración original, o el compilador emite un error.

Varianza, Covarianza y Contravarianza

En los sistemas de tipado estático, existe este concepto de varianza, que a veces puede entenderse muy fácil pero tampoco es tan intuitivo como parece.

Para ilustrar la varianza, vamos a definir una jerarquía de clases muy simple:

 

Y definimos un método o función que usa estos tipos:

 

Primero que nada, viéndolo desde fuera, ¿A qué tipo de variables podemos asignar lo que devuelve esta función?

 

Las primeras dos líneas son correctas, la tercera da un error. Esto es porque la función devuelve un valor de tipo B, y B es también un A. Pero no podemos asignar a una subclase de B, al menos no sin hacer un cast, pero no vamos a hacer casts en esta ocasión. B no es un C, por lo tanto la tercera línea no compila.

Hasta aquí todo bien. Ahora, ¿Qué le podemos pasar como argumento a esta función? Tiene un solo parámetro de tipo B. En esta ocasión, es alrevés:

 

Hystrix: primer contacto

En la conferencia de Software Guru de este año, Agustín Ramos dio una charla acerca de sistemas tolerantes a fallas, en la cual mencionó un software que me llamó mucho la atención, llamado Hystrix, desarrollado por Netflix.

La idea de Hystrix es que en sistemas que se comunican mucho con otros sistemas por medio de red, poder aislar todas esas llamadas a servicios externos y permitir que sean administradas de forma robusta, es decir, que haya un control de conexiones salientes, mantener buenos tiempos de respuesta, con tolerancia a fallas integrada.

Esto suena muy bien: si tengo un sistema que hace llamadas constantes a un web service externo, generalmente el funcionamiento de ese web service afecta el funcionamiento de mi sistema: Si de repente se pone lento, se tarda mucho en contestar, mi sistema empieza a sentirse lento, porque está esperando respuesta del sistema externo. Luego empiezan los problemas porque resulta que mi sistema encola las llamadas a dicho web service, precisamente para no saturarlo, pero pues está lento y eso está fuera de mi control pero resulta que las llamadas encoladas ya se tardan mucho tiempo en ejecutarse, es decir, la tardanza del web service no solamente se convierte en esperar respuesta del mismo, sino que hay llamadas que se quedan mucho tiempo encoladas y entonces puede que ya salgan muy tarde. ¿Y si hay un usuario en línea esperando la respuesta? ¿Y si el sistema ya le respondió error, incluso antes de que siquiera se realice la llamada al servicio externo?

Distribuir contenido