La palabra clave assert de Java y un ejemplo

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Aunque no es muy utilizada, para tareas de depuración es una ayuda que bien empleada permite descubrir el origen de algún bug en un programa. Los asserts en Java son ignorados, por tanto no suponen ninguna penalización en tiempo de ejecucción, salvo que se indique de forma explicita en la ejecución del programa, esto permite añadirlos al código fuente y activarlos en el momento que se desee realizar una depuración para encontrar errores.

Java

La palabra clave o reservada assert sirve para aseverar que en un determinado momento del código una determinada condición debe ser cierta. Está disponible en Java desde la versión 1.4 pero al menos yo con bastantes años de experiencia en programación en este lenguaje aún no he usado de forma amplia y posiblemente le pase a mucha de la gente y aún así hemos sobrevivido durante todo este tiempo.

Sin embargo, puede resultarnos bastante útil. Una de las situaciones en que puede ayudarnos es para descubrir una condición no válida en el momento del assert y no donde se produce una excepción en otro punto del código que puede no ser la causa real del error. Por ejemplo, supongamos que un método privado no acepta un parámetro con valor null, una variable no puede ser null o una colección no ha de estar vacía por poner solo unos pocos ejemplos de condiciones, si en un punto del código estamos seguros que es un error que esa condición sea falsa podemos hacer que el programa falle con una excepción ahí y no más tarde a consecuencia de que las condiciones no se cumplían. Otra forma en la que nos ayudan los assert es como documentación, en vez de poner un comentario o en el javadoc indicando una condición que se ha de cumplir podemos ponerlo con un assert. Normalmente se usan en:

  • Precondiciones: en métodos privados que el llamador ha de cumplir.
  • Postcondiciones: para verificar el resultado prometido por el método.
  • Class invariants: para validar el estado de una clase según está definido en su contrato, siempre se debe cumplir independientemente de las operaciones que se realicen.
  • Código no alcanzable en tiempo de ejecución: partes del programa que se espera que no sea alcanzable, como cláusulas else o default en sentencias switch.

Y no deben usarse para:

  • No se deben usar para comprobar argumentos en métodos públicos: los asserts pueden habilitarse o deshabilitarse, comprobar los argumentos se considera parte de las responsabilidades del método y su especificación.
  • No se deben usar para realizar tareas: ya que los asserts pueden deshabilitarse las tareas dejarían de ejecutarse y de proporcionar la funcionalidad del programa.

Nos pueden entrar dudas de cuando emplear un assert y cuando un if o una excepción. Las excepciones se encargan de hacer que el programa sea robusto controlando las situaciones inesperadas pero posibles, los assert se encargan de que el programa sea correcto. Los assert deberían ser usados para asegurar algo, mientras que las excepciones deberían usarse para comprobar algo que podría ocurrir. Un assert termina la ejecución (ya que no se suele capturar la excepción que se produce) mientras que una excepción permite al programa continuar con la ejecución. Los asserts no deben ser sustitutos de condiciones de validación que debería hacer el programa en métodos públicos de una clase. Los assert son una herramienta en tiempo de desarrollo, las excepciones además son una herramienta para la ejecución en producción.

Un pequeño ejemplo de los asserts podría ser el siguiente en la que en el método nextNumber hay una postcondición según la cual el método debe devolver un número entero entre 0 y 9 (incluidos):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package io.github.picodotdev.blogbitix.asserts;

import java.util.Random;

public class Main {

	private Random random;
	
	public Main() {
		random = new Random();
	}

	/**
	 * Devuelve un número entero entre 0 y 9.  
	 */
	public int nextNumber() {
		int i = random.nextInt(40);

		// Si el cálculo del número fuese más complejo incluyendo un assert
		// podemos asegurar en tiempo de desarrollo en esta postcondición
		// el valor generado por este método.
		// La línea de código anterior según el contrato del método debería ser:
		// int i = random.nextInt(10);
		assert i >= 0 && i < 10: String.format("El número devuelto no cumple la postcondición (%d)", i);
		
		return i;
	}
	
	public static void main(String[] args) {
		Main main = new Main();
		System.out.println(main.nextNumber());
	}
}
Main.java

Un assert cuya expresión se evalúa como falso produce una excepción del tipo java.lang.AssertionError pero para ello se han de habilitar en tiempo de ejecución como el parámetro -ea de la máquina virtual. En eclipse podemos cambiarlo en la configuración de ejecución del programa en la pestaña Arguments y VM arguments tal como se ven en la siguiente captura de pantalla:

Activación asserts en eclipse

En la primera de las siguientes capturas de pantalla puede verse como el programa se ejecuta sin producir una excepción a pesar de no cumplirse el assert del método nextNumber ya que los asserts no fueron activados, en la segunda captura activando los assert se lanza una excepción al no cumplirse la postcondición.

Ejecución sin excepción

En el recomendable artículo Programming With Assertions se comenta de forma más detallada y amplia el funcionamiento y uso adecuado de la palabra clave assert de Java.

El funcionamiento de los assert en Groovy es distinto. En groovy los assert no pueden deshabilitarse, están siempre habilitados y por tanto no hace falta usar el parámetro -ea de la máquina virtual que empleamos en Java, no es un bug es una feature. Por el contrario, en Java los asserts se consideran una herramienta en tiempo de desarrollo o depuración y por tanto podemos habilitarlos mientras desarrollamos y no habilitarlos en producción, una de las razones es que los asserts pueden suponer una penalización de rendimiento si las comprobaciones son costosas en tiempo o carga de CPU cosa que no queremos en producción donde el código ya se considera correcto.


Comparte el artículo: