post icon

La polemica del String en el Switch de Java

Si las cosas van como lo planeado dento de poco tiempo veremos a la luz a Java en su versión 7 y consigo trae un montón de detractores y apologístas de los cambios que veremos. Unos dicen que se está apuntando hacía cualquier lugar, otros que la evolución es muy lenta y la competencia crece demasiado, otros que los cambios que se harán son de menor prioridad y se deberían priorizar otros aspectos, en fín, leerán a muchos opinar sobre el tema y no quiere decir que uno u otro esté mal, muchos argumentos me han gustado en la manera que lo han usado para defender sus ideas. La propuesta la pueden leer aquí (Inglés requerido).

En mi percepción hasta el momento, la caracteristica más polemica es la nueva posibilidad de evaluar el tipo de dato String dentro de la sentencia Switch. Hasta ahora sólo se puede evaluar tipos de datos que puedan tener un cast a int (int, Integer, byte, Byte, short, Short, char, enum y Character) y como String no puede pasar de ninguna manera a ser un int es rechazado.

Personalmente me parece muy útil en la práctica evaluar valores String, es màs intuitivo a la hora de leer el código

String valor = "otro valor";
switch (valor) {
	case "un valor":
		break;
	case "otro valor":
		break; // ejecutará este bloque
}

Una práctica común que he visto mucho es que le sacan el hash al texto y evaluan eso. La posibilidad de error es remota pero existe, nadie nos garantiza que el hash para 2 String no sea el mismo además que es costoso su entendimiento al leerlo.

String valor = "otro valor";
switch (valor.hashCode()) {
	case 6345553:
		break;
	case -4542235:
		break; // ejecutará este bloque
}

Creo que se comprende porque desde el punto de vista práctico es útil ésta nueva caracteristica, pero también debemos ver el otro lado de la moneda, el punto de vista técnico. Con esto podremos comprender la película completa.

Todo se remonta a la creación de la clase String, que fue creada con un comportamiento no-intuitivo en Java. A la hora de compararse no se hace por medio del valor que contienen sino por las referencias en memoria de la misma. Es por eso que cuando hacemos ésta comparación siempre nos retornará false.

boolean comparar() {
	return new String("devtroce") == new String("devtroce");
}

El motivo porque ésta comparación da falso, es que se crean 2 instancias en memoria, es decir, 2 referencias y se comparan esas referencias y no su valor contenido por ende nunca serán iguales. Más de uno me dirá pero si haces ésto retornará true.

boolean comparar() {
	return "devtroce" == "devtroce";
}

Aunque a primera vista parezca que comparó los valores por eso retornó true, lo que sucedió es que el compilador en su afán de optimizar la aplicación ya conoce los caminos posibles de ejecución entonces tan sólo crea una sola referencia para 2 objetos iguales, y a la hora de compararlos se compara contra sí mismo. Pero que sucede si no comparamos valores que el compilador pueda interpretarlos anticipadamente.

boolean comparar() {
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	String algo = br.readLine();
	return "devtroce" == br;
}

Así no existe modo que el compilador conozco el valor que introduciremos y se volverán a crear 2 referencias para los objetos String.
Ustedes que opinan al respecto? espero sus comentarios..

20 noviembre 2010

Comentarios desde Facebook:

  1. avatar
    Gustavo COLOMBIA Mozilla Firefox Windows
    20 marzo 2011 at 19:30 #

    Gracias por tu aporte estaba buscando como hacer un Switch Case en java evaluando un String. Ya me quedo claro porque me arroja error.
    Mil gracias, muy bien explicado
    De casualidad me puedes orientar sobre como hacer esa comparacion de cadenas en un Switch-Case que no sea con el hashCode ? A mi mail podria ser Gracias !!

    Gustavo

Responder