Translate
martes, 3 de septiembre de 2019
Optional, la solución de Java 8 para NullPointerException, Parte 3
El patrón Optional es un patrón nacido en los lenguajes funcionales (sobre todo Scala), por lo que usarlo de una manera imperativa hace que no sea eficiente.
Optional<Double> getDurationOfAlbumWithName(String name) {
Optional<Double> duration = getAlbum(name)
.flatMap((album) -> getAlbumTracks(album.getName()))
.map((tracks) -> getTracksDuration(tracks));
return duration;
}
Usando las funciones map y flatMap acortaríamos un código relativamente complicado a solo 3 lineas, vamos a repasar paso por paso donde está el truco.
Para ello vamos a ver el método map de la clase Optional que es lo que hace:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
Dentro de esa signatura complicada se encuentra algo bastante sencillo, es un método que admite una función, la cual a su vez admite un Optional, esta función ha de devolver un valor del tipo que acepta. Lo que hace la función es más fácil de ver, comprueba si el Optional está vacío, si lo está devuelve un Optional vacío y si no, aplica la función que le hemos pasado por parámetro, pasándole el valor del Optional
Es decir, si el Optional está vacío, el método map no hace nada, esto es primordial para poder concatenar operaciones sin necesidad de comprobar a cada momento si el
Optional está vacío.
Antes de seguir con ejemplo, comentar el uso del método flatMap, y es que cuando queremos encadenar distintas operaciones que devuelvan Optional, es necesario usar
flatMap ya que si no acabaríamos teniendo un Optional<Optional<Double>>
Si lo extraemos paso a paso, podemos ver que no hay magia por ningún lado:
Optional<Album> albumOptional = getAlbum(name);
Optional<List<Track>> listOptional = albumOptional.flatMap((album) -> getAlbumTracks(album.getName()));
Optional<Double> durationOptional = listOptional.map((tracks) -> getTracksDuration(tracks));