¿Cuáles son algunas de las características menos conocidas de Google Guava que todo desarrollador puede usar?

Google Guava

Es una de las librerías más populares que hay, es de código abierto, probablemente ya sabes de qué hablamos, y viene de un lugar donde la gente juega Quidditch como un deporte real (al menos en The Internship). No es la librería Hogwarts de Harry Potter pero sí que tiene unos cuantos hechizos bajo la manga: Google Guava contiene variedad de librerías clave de Java que nacieron dentro de Google, fueron puestas a prueba en el combate en producción y entonces se lanzaron públicamente. Y también tenía Optional antes de que apareciera en Java 8.

El objetivo principal de Guava es la mejora del flujo de trabajo destinado a tareas comunes con utilidades que ayuden a escribir un mejor código, uno más limpio, y a ganar en productividad. Más famosa por su capacidad de almacenamiento temporal (caching) y sus colecciones, contiene asimismo muchas más características que, aunque sumamente beneficiosas, no son muy conocidas. Para las colecciones y el almacenamiento temporal, nuevas mejoras fueron presentadas en la API JDK Collections y asimismo se llenó el vacío generado por la reclamada (y tan esperada) JCache, que finalmente fue lanzada el año pasado. En este artículo, me gustaría compartir contigo algunas de la características de Google Guava que nos gusta usar aquí en OverOps y algunos otros descubrimientos interesantes que hemos hecho recientemente.

Nota: Guava soporta Java 6 en adelante.

1. Primitivos sin signo: ¡Sí, existen!

Una de las características menos conocidas de Java 8 es un nuevo enfoque de los Primitivos sin Signo en la clase Integer. Otra característica, aún menos conocida, de Guava es el hecho de que todo esto ya había estado disponible años antes del lanzamiento de Java 8 y hoy en día puede ser usado desde Java 6 en adelante. Veamos cómo son manejados en Guava. Tenemos dos opciones ante nosotros, así que la consistencia dependerá justamente de nosotros:

Tratar al tipo primitivo directamente como int (entero), mientras recordamos que es Sin Signo, en nuestra lógica:

int notReallyInt = UnsignedInts.parseUnsignedInt(4294967295); // Max unsigned int

String maxUnsigned = UnsignedInts.toString(notReallyInt); // We’re legit!

UnsignedInts y UnsignedLongs también soportan métodos tales como compare, divide, min, max y otros.

Un wrapper (clase envolvente) para evitar el trato directo con primitivos y causar errores:

UnsignedInteger newType = UnsignedInteger.valueOf(maxUnsigned);

newType = newType.plus(UnsignedInteger.valueOf("1")); // Increment

UnsignedInteger y UnsignedLong también soportan métodos tales como minus, times, dividedBy y mod.

Averigua más en la wiki de Guava

2. Hashing: MurmurHash de 128 bits por la victoria

Buscando entre las posibilidades de hashing no criptográfico que obtenemos con la librería estándar de Java, una cosa de la que realmente sentimos la falta es el MurmurHash. Es simple, veloz, distribuido de forma pareja, y tiene un gran soporte en varios idiomas. No es tan bueno como para reemplazar al hashCode() de Java, pero es perfecto si quieres generar muchos hashes, cuando 32 bits no son suficientes, y necesitas que eso quede hecho en tiempo récord sin dañar el desempeño. Así es como funciona en Guava:

HashFunction hf = Hashing.murmur3_128(); // 32bit version available as well
HashCode hc = hf.newHasher()
.putLong(id)
.putString(name, Charsets.UTF_8)
.putObject(person, personFunnel)
.hash();

La descomposición de los objetos es realizada usando un Funnel que contenga instrucciones sobre cómo leer el objeto, así si tenemos una Person con una id (identificación), name (nombre) and birth year (año de nacimiento):

Funnel<Person> personFunnel = new Funnel<Person>() {
@Override
public void funnel(Person person, PrimitiveSink into) {
into
.putInt(person.id)
.putString(person.firstName, Charsets.UTF_8)
.putString(person.lastName, Charsets.UTF_8)
.putInt(birthYear);
}
};

Averigua más en la wiki de Guava

3. InternetDomainName: reemplazará tu herramienta de validación de nombre de dominio

Otra pequeña e interesante utilidad que viene con Guava es un InternetDomainName, que, para tu sorpresa, te ayuda a analizar y manipular nombres de dominio. Si alguna vez tú mismo escribiste una utilidad similar, de seguro apreciarás cómo esto ayuda a resolverlo rápidamente, y de una manera muy elegante. Y válida de acuerdo con las especificaciones RFC más actualizadas, usando la lista de dominios de la Public Suffix List, una iniciativa de la Fundación Mozilla. En general también tiene métodos más específicos que la herramienta de validación equivalente de Apache-commons. Veamos un breve ejemplo:

InternetDomainName owner =
InternetDomainName.from("blog.overops.com").topPrivateDomain(); // returns takipi.com

InternetDomainName.isValid(“takipi.monsters"); // returns false

He aquí algunos conceptos relacionados a los nombres de dominio que pueden suscitar confusión:
publicSuffix() – El dominio superior, que es una entidad separada de acuerdo a la Public Suffix List. Así que tendremos resultados como co.uk, .com, .cool (sí, es un sufijo real, y javais.coolscalais.cool).
topPrivateDomain() – El dominio superior, que es una entidad separada de acuerdo a la Public Suffix List (PSL). Al aplicarlo en blog.overops.com, devuelve overops.com, PERO si lo intentas en un sitio de las páginas Github, username.github.io devolverá username.github.io pues es una entidad separada que aparece en la PSL.

Esta utilidad es de ayuda cuando necesitas validar dominios, como en el caso de la integración con JIRA que recientemente realizamos en OverOps, donde primero verificamos tu host JIRA, antes de conectarlo a la herramienta de análisis de errores de producción de OverOps.

Averigua más en la wiki de Guava

4. Reflexión de ClassPath: Espejito, espejito mágico en la pared

Al inspeccionar la capacidad de reflexión de Java, la habilidad de inspeccionar tu propio código, verás que no existe una forma sencilla de obtener una lista de todas las clases de tu paquete o proyecto. Esta es una de las características de Guava que realmente nos encanta, ya que ayuda a obtener más información sobre el entorno en que estás trabajando. Funciona tan simple como esto:

ClassPath classpath = ClassPath.from(classloader);
for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses("com.mycomp.mypackage")) {
System.out.println(classInfo.getName());
}

Este snippet recorrerá e imprimirá todos los nombres de clases en el paquete que le hayamos especificado. Algo que vale la pena mencionar aquí es que este escaneo comprende únicamente a aquellas clases que estén ubicadas físicamente bajo el paquete que mencionamos. No incluirá clases cargadas desde otros lugares, así que debes tener cuidado con qué uso le das, pues a veces puede darte un panorama incompleto.

Averigua más en la wiki de Guava

5. CharMatcher: ¿Regex simplificada?

Vamos a terminar este resumen de varias características con otro problema que estoy seguro que te sonará conocido. Tienes un String o una serie de Strings a los que quieres darle cierto formato, quitarles los espacios u otro caracteres, reemplazar un carácter en particular, extraer los dígitos o quién sabe qué más. Lo más común es tomar caracteres que cumplen con cierto patrón y hacer algo con ellos. Guava aquí brinda el método CharMatcher para manejar tales problemas de una manera elegante.

Para dicha tarea, contamos con algunos patrones predefinidos  como JAVA_UPPER_CASE (para caracteres en mayúscula), JAVA_DIGIT (dígitos), INVISIBLE (caracteres Unicode invisibles) y muchos más. Más allá de los patrones predefinidos, también nosotros podemos meter mano y crear nuestros propios patrones. Veamos cómo funciona esto con un rápido ejemplo de código:
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ‘ ‘);

Esto quitará todos los espacios desde el final del string y combinará todos los subsiguientes espacios en uno.

String keepAlex = CharMatcher.anyOf(“alex”).retainFrom(someOtherString);

Esta línea tomará un String y lo despojará de todos los caracteres que no aparecen en mi nombre. Si alguna vez llego a ser un rapero, así empezarían todas mis canciones

Averigua más en la wiki de Guava

Conclusión

Hemos visto algunas de las características más interesantes de Google Guava, sin incluir las tan populares librerías caché y de colecciones. Algunas de ellas son usadas -y mucho- en OverOps, y otras son de gran utilidad, así que creemos que muchos proyectos podrían beneficiarse de ellas. Google Guava ayuda a los desarrolladores a ser más productivos, y eso es precisamente a lo que aspiramos aquí en OverOps con las herramientas que estamos desarrollando (que de paso están muy buenas, pero bueno, puede que yo no sea muy imparcial: será mejor que tú mismo las pruebes).

Nos mata la curiosidad, ¿qué otras características de Guava usas que la mayoría de los desarrolladores ignoran? (¡No valen las colecciones y las de almacenamiento temporal!). Cuéntanos tus ideas en la sección de comentarios de más abajo, por favor.

Some kind of monster @ OverOps, GDG Haifa lead.