Java 7: Hacia dónde va y por qué no me gusta

Para aquellos que no hayan visto nada de Java 7, el “Project Coin” ha aprobado cinco (realmente siete) nuevas características. Voy a comentar algunas de ellas y, como habréis notado por el título del post, a explicar por qué no me gustan.

Strings en switchs

Como todos sabéis, en Java no está permitido el uso de strings en los switchs. Básicamente un switch sólo permite la evaluación de aquellos tipos que puedan tener un cast a int (int, byte, short, char, enum, Character, Byte, Short e Integer). String no es ahormable a int y por tanto no se acepta. Ahora bien, en la práctica, es útil hacer switchs con strings, así que con esta propuesta el siguiente código será válido:

        String valor = "algo";
        switch (valor) {
            case "otra cosa":
                break;
            case "algo":
                //este código será ejecutado
                break;
        }

No me cabe ninguna duda de que es mucho más legible que soluciones actuales, como la siguiente:

        String valor = "algo";
        switch (valor.hashCode()) {
            case -1850569338:
                break;
            case 2996819:
                //este código será ejecutado
                break;
        }

Sin embargo, aunque veo su utilidad, estoy en contra de esta modificación. ¿Por qué? Porque el comportamiento de String se convierte en una casa de putas.

El funcionamiento teórico del switch es simple, una variable será comparada con N alternativas, y si alguna de ellas coincide, se ejecutará esa porción de código. Todos tenemos claro que un int de valor 5 es igual a otro int de valor 5, pero un String con valor “hola” no es igual a otro String de valor “hola”… simplemente la clase String tiene un comportamiento contra-intuitivo. Veamos un ejemplo:

    boolean siempreFalso() {
        return new String("hola") == new String("hola");
    }

Mucha guitarra, pero siempre los mismos acordes…

En contra de lo que uno podría pensar, ese método siempre retornará false. El operador de igualdad no compara el valor de las cadenas, sino sus referencias en memoria, y dado que ambos “hola” no son el mismo objeto, la comparación se probará falsa. Esto no ocurriría en el caso de un switch, ya que se compararía el valor y no la referencia.

[Edición: Javier Collado ha caido en la cuenta de que el ejemplo era un poco artificioso, leed los dos primeros comentarios para tener una explicación de por qué]

Desarrolladores de Java, centren la pelota. O hacemos que String no mire el valor sino la referencia, por ortogonalidad aunque sea contra-intuitivo, o hacemos que mire el valor y que le den a la ortogonalidad. Pero hacer una clase String que sea ortogonal para luego decir que eso es muy molesto y modificar otras partes del lenguaje para que String se comporte de forma no ortogonal, me parece que es hacer el idiota. Con todo el cariño y respeto del mundo.

Mejora de la inferencia de tipos en la creación de instancias genéricas

La verdad es que el título en inglés suena bastante mejor, “Improved Type Inference for Generic Instance Creation“. Como dirían en mi pueblo, mucha mecha para tan poca dinamita. Tras este nombre tan rimbombante se oculta una característica que busca reducir la verbosidad de los tipos genéricos. Atención a la jugada, primero pongo la linea actual, y luego como quedaría en Java 7:

//Actual
ArrayList<String> miListaDeStrings = new ArrayList<String>();
 
//Java 7
ArrayList<String> miListaDeStrings = new ArrayList<>();

Acojonante, siete versiones para esto ¬¬. Lo más gracioso del tema es que en la propia propuesta se dice que otras alternativas serían mejores, pero se elige esta porque, o bien no se necesitan otras, o bien tendrían demasiadas desventajas.

¿Alguien se pregunta por qué está ahí el <>? Pues porque si por ejemplo tienes un objeto Map sin parametrizar, se asume que son datos crudos, no que estás infiriendo el tipo. Así que para mantener la compatibilidad hacia atrás, se ponen los <>.

Si no he entendido nada mal, la compatibilidad a nivel de bytecode no se ve comprometida, simplemente las aplicaciones obsoletas que no tengan en cuenta estos cambios, deberían compilarse contra el JDK para el que fueron diseñadas. Amén de que este problema me parece una cosa menor, me hace gracia que piensen que esta pijada de inferencia es significante. Daos cuenta que esto no funciona si queremos inferir un lvalue… no se ha implementado ningún tipo de tipo de inferencia como “auto” en C++ o “var” en C#, no. Esto sólo sirve para las creaciones. No es que sea un juguete… es que es un juguete.

Aparentemente a los desarrolladores de Java no les ha parecido interesante poder hacer cosas como esta:

//Oh, sin lvalues es imposible hacer esto
auto mejorCliente = metodoQueDevuelveElMejorCliente();
 
//así inferiríamos el tipo de la colección. Java 7 FAIL
for(auto cliente : metodoQueDevuelveUnaColeccionDeClientes()) {
}

Identificadores exóticos

Los identificadores exóticos están aquí por la proposición JSR292, que trata principalmente de hacer la JVM accesible a lenguajes dinámicos. Un identificador exótico nos permitiría llamar a una variable “mira que nombre tan mono”. Lo siguiente sería correcto:

int #"mira que nombre" = 22;
System.out.println(#"mira que nombre"); // muestra 22

Vamos a ver, por mi perfecto, pero ¿no había más caracteres en el universo? ¿les pagan por popularizar #? Ojo al dato:

int x = 22;
int #"x+100" = 100;
System.out.println(#"x+100"); // Muestra 100;
System.out.println(#()x+100); // Muestra 122;

Es un ejemplo y puede ser rebuscado, sí. Pero ahora decidme que nunca habéis puesto donde no era unas comillas y unos paréntesis… sobre todo con la manía que tienen los IDEs de decidir por tí donde poner dobles comillas o cerrar los paréntesis.

¿Por qué es válida la segunda línea? Por la inclusión de los cierres lambda. El compilador no detectará ningún error porque no lo entenderá como un identificador exótico ni como una expresión inválida, sino como un cierre lambda.

Personalmente hubiera preferido que el indicador de una expresión lambda fuera “->” o “<-“.

Conclusión

Podría seguir con otras características, pero voy a parar aquí porque esto está quedando muy largo. Sin duda muchas de las características implementadas son útiles y resuelven problemas reales. Mi crítica es más bien que ese trabajo es bueno, pero corto. Con la impresión que me quedo después de haber leído las propuestas es que el excesivo celo por la compatibilidad, la peculiar forma que tienen de entender la ortogonalidad y la falta de innovación parece llevarles a un “quiero y no puedo”.

¿Qué opináis vosotros?

About the Author

Me llamo Pablo Carballude González, soy graduado en computación con master en HCI y Seguridad Informática. Actualmente trabajo para Amazon en Seattle como Software Developer Engineer. Soy de esas personas que no saben si los textos autobiográficos deben ser en primera o tercera persona. Lo intenté en segunda, pero no le entendí nada :P