Inclusión condicional de bloques de código en Java mediante constantes

31Jul08

Java a diferencia de otros lenguajes(como C, C++, …) no poseé directivas de preprocesador que permiten incluir/excluir bloques de sentencias a partir de cierta condición.

Lo que podemos realizar es simular un comportamiento parecido conociendo las optimizaciones llevadas a cabo por el compilador al procesar nuestro codigo fuente.

Como hemos visto anteriormente, cada vez que el compilador tenga la posibilidad de inferir que algo va a ser invariante a lo largo de la ejecución del programa, realizara una optimización que no afecten los resultados del mismo. Por ejemplo si encuentra:

String estadoInicial = "Estado Inicial: " + 25;
int tiempoEspera = 15 * 60 * 1000; //15 minutos en milisegundos

al realizar la compilación quedará:

String estadoInicial = "Estado Inicial: 25";
int tiempoEspera = 900000;

De esta misma forma si puede resolver la condición de un if, puede decidir si la condición es true que bloque se debe ejecutar siempre:

System.out.println("Antes");
if(true){
	System.out.println("Ejecutando...");
}
System.out.println("Despues");

compilando:

System.out.println("Antes");
System.out.println("Ejecutando...");
System.out.println("Despues");

Lo interesante se produce en el caso contrario, si encuentra un false en la condición, el bloque no es incluido en los .class generados:

System.out.println("Antes");
if(false){
	System.out.println("Ejecutando...");
}
System.out.println("Despues");

dejarando:

System.out.println("Antes");
System.out.println("Despues");

Para que puede servirnos esto?

Entre otras cosas para realizar debug de la aplicación permitiendo que, según como se encuentre una costante, se incluyan ciertas sentencias o no.

Veamos un ejemplo donde se utilizan dos tipos de constantes, una booleana y otra entera:

class A{
	public static final boolean EN_DEBUG = false;
	public static final int UN_NIVEL = 25;
	//...
	public void unMetodo(){
		//...
		if(UN_NIVEL < 100) hacerAlgo1();
		if(UN_NIVEL > 75) hacerAlgo2();
		//...
	}
}

class B{
	public void unMetodo(){
		//...
		int res = otroMetodo1();
		if(A.EN_DEBUG){
			System.out.println("El resultado de otroMetodo1 es: " + res);
		}
		otroMetodo2(res);
		//...
	}
}

Al actuar el compilador nos quedará:

class A{
	public static final boolean EN_DEBUG = false;
	public static final int UN_NIVEL = 25;
	//...
	public void unMetodo(){
		//...
		hacerAlgo1();
		//...
	}
}

class B{
	public void unMetodo(){
		//...
		int res = otroMetodo1();
		otroMetodo2(res);
		//...
	}
}

permitiendonos ejecutar determinado código, que cuando la aplicación se encuentre en produccion no lo ejecutará pero tampoco tendrá problemas de rendimiento, ya que ese codigo directamente no es incluido en la solución final.




A %d blogueros les gusta esto: