Tutorial sobre la clase Optional a profundidad


La clase Optional se introdujo en Java 8 y se utiliza para representar si un valor esta presente o no, esto ayuda a crear apis limpias y a evitar posibles NullPointerExceptions.

A continuación algunos ejemplos sobre como utilizar Optional en una aplicación:

Ejemplo Básico

Supongamos que tenemos el siguiente código:

public Person findPersonByName(String name) {
	return dao.findPersonByName(name);
}

El código a simple vista parece no tener ningún problema, ahora veamos el código que lo utiliza:

public void validate(String name) {
	Person result = findPersonByName(name);
	boolean adult = result.getAge() > 18;
	/**
	 * Other calculations 
	 */
}

Como vemos el método validate utiliza a findPersonByName para con base en el nombre determinar si es o no un adulto, el código no tendría ninguna falla siempre y cuando el nombre que se pasa como parámetro existe en la base de datos, en caso contrario se produciría una NullPointerException.

Veamos como solucionarlo sin utilizar la clase Optional:

public void validate(String name) {
	Person result = findPersonByName(name);
	if(result!=null){
		boolean adult = result.getAge() > 18;
	}else{
		/**
		 * take different actions
		 */
	}
}

La solución es funcional pero no es muy práctica, ya que depende mucho de quien consume el método realizar la validación o no.

Veamos la solución utilizando la clase Optional:

public Optional<Person> findPersonByName(String name) {
	return Optional.ofNullable(dao.findPersonByName(name));
}

public void validate(String name) {
	Optional<Person> result = findPersonByName(name);
	if (result.isPresent()) {
		boolean adult = result.get().getAge() > 18;
	} else {
		/**
		 * take different actions
		 */
	}
}

Como vemos el método findPersonByName() busca a la persona por nombre y utiliza Optional.ofNullable() para indicar que es posible que se tenga un valor nulo. Al devolver un objeto de tipo Optional en lugar de uno de tipo Person se da a conocer a los consumidores del api que el valor de retorno del método puede ser nulo así que deben utilizar el método isPresent para validar si existe el valor o no. Esto lo hace una solución muy elegante a demás que se evita generar NullPointerExceptions para casos cuando es posible tener un elemento nulo.

Utilizando valores por defecto 

Existen casos cuando en caso de no existir un valor tal vez quieres utilizar un valor por defecto en lugar de devolver la referencia null, veamos el siguiente ejemplo:

public Properties getApplicationProperties() {
	Properties props = new Properties();
	props.setProperty("applicationName", "Great application");
	return props;
}

public void configureCluster(){
	Properties properties = getApplicationProperties();
	String context= Optional.ofNullable(properties.getProperty("contextPath")).orElse("/api");
	System.out.println(context);
}

public static void main(String[] args) {
	new Configuration().configureCluster();
}

Si ejecutamos el código anterior la salida será /api porque obtenemos la propiedad contextPath, al ser nula devolvemos el valor /api utilizando el método orElse().

En el ejemplo anterior vimos como utilizar el método orElse(), la limitante que tiene es que recibe un objeto del mismo tipo que el objeto opcional así que solo podremos poner un valor en el sin lógica, existe una version similar llamada orElseGet() la cual en lugar de tomar el valor a devolver en caso de que el valor no se encuentre presente tomará una interfaz funcional la cual solo se invocará en caso de que el elemento no se encuentre presente.

Veamos un ejemplo

public void configureCluster() {
	Properties properties = getApplicationProperties();
	String context = Optional.ofNullable(properties.getProperty("contextPath")).orElseGet(() -> 
	getContextPathFromRemoteService()
	);
	System.out.println(context);
}

public String getContextPathFromRemoteService() {
	return Math.random() + "";
}

Como vemos, en caso de que la propiedad ‘contextPath’ no se encuentre en nuestro objeto properties se mandará a llamar el método getContextPathFromRemoteService(). 

Lanzando excepciones

En el ejemplo anterior vimos como devolver un valor por defecto en caso de que algo no esté presente, ahora veremos como mandar una excepción, veamos el siguiente ejemplo:

public Properties getApplicationProperties() {
	Properties props = new Properties();
	props.setProperty("applicationName", "Great application");
	return props;
}

public void configureCluster() {
	Properties properties = getApplicationProperties();
	String context = Optional.ofNullable(properties.getProperty("contextPath")).orElseThrow(IllegalStateException::new);
	/**
	 * configuring the application
	 */
}

Como se puede ver modificamos el ejemplo anterior para que en caso de que no se encuentre la propiedad contextPath se genere una excepción IllegalStateException y detenga el inicio de la aplicación.

En el siguiente post veremos como utilizar la clase Optional en conjunto con Streams.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales  https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s