Je suis curieux de savoir pourquoi la méthode Facultatif de Java ne fournit pas une méthode peek
semblable à celle de Stream
.
La méthode peek
javadoc de l'interface Stream
indique:
- @apiNote Cette méthode existe principalement pour prendre en charge le débogage, où vous souhaitez voir les éléments lorsqu'ils dépassent un certain point dans un pipeline.
Ceci décrit presque exactement mon cas d'utilisation:
@Override
@Transactional
public User getUserById(long id) {
return repository.findById(id)
.peek(u -> logger.debug("Found user = {} by id = {}", u, id))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
}
(repository.findById
renvoie Optional<User>
(voir CrudRepository # findById ))
Mais il ne compilera pas car il n'y a pas de méthode peek
sur Optional
.
Donc, sans la méthode peek
, tout ce qui précède se transforme en:
@Override
@Transactional
public User getUserById(long id) {
Optional<User> userOptional = repository.findById(id);
if (userOptional.isPresent()) {
logger.debug("Found user = {} with id = {}", userOptional.get(), id);
}
return userOptional.orElseThrow(() -> new UserNotFoundException("id = " + id));
}
Il est également possible de faire quelque chose comme ceci (voir ceci réponse ):
@NoArgsConstructor(access = PRIVATE)
public abstract class OptionalUtils {
public static <T> UnaryOperator<T> peek(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
}
Et utilisez-le avec la méthode map
:
return repository.findById(id)
.map(OptionalUtils.peek(u -> logger.debug("Found user = {} with id = {}", u, id)))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
Mais je pense que ceci est un hack plutôt qu'un usage propre de Optional
.
Depuis Java 9, il est possible de transformer Optional
en Stream
mais le flux n’a pas la méthode orElseThrow
(et il ne devrait évidemment pas en être ainsi).
De plus, il est possible de faire la même chose en utilisant ifPresent
mais il retourne void
. (Et pour moi, il semble que ifPresent
ne retourne rien d'autre que void
)
Est-ce que j'utilise mal Optional
?
L'absence de la méthode peek
est-elle intentionnelle? (Mais en même temps, Option
de Vavr fournit la méthode peek
.)
Ou était-ce juste considéré comme ne valant pas la peine?
Eh bien, seuls les concepteurs peuvent vous répondre avec les détails "exacts" expliquant pourquoi il n’existait pas de méthode Peek pour Optionals.
Donc, pour l'instant, vous êtes coincé avec l'utilisation de isPresent()
, qui me semble tout à fait bien:
if (userOptional.isPresent())
logger.debug("Found user = {} with id = {}", userOptional.get(), id);
ou vous pouvez envisager les réponses suggérées sur la page liée si vous le souhaitez dans le cadre du pipeline.
en passant, étant donné la nouvelle méthode stream
à partir de JDK9, vous pourriez faire:
return repository.findById(id) // Optional<User>
.stream() // Stream<User>
.peek(u -> logger.debug("Found user = {} by id = {}", u, id)) // Stream<User>
.findFirst() // Optional<User>
.orElseThrow(() -> new UserNotFoundException("id = " + id))
Il existe déjà la méthode Optional::ifPresent
qui accepte une Consumer
.
En Java 8, le seul moyen est d’utiliser Optional::map
, pour mapper l’entité sur elle-même et l’utiliser comme méthode peek
:
return repository.findById(id)
.map(u -> {
logger.debug("Found user = {} with id = {}", u, id)
return u;
})
.orElseThrow(() -> new UserNotFoundException("id = " + id));
... qui doit être simplifié en implémentant une méthode peek
propre:
<T> UnaryOperator<T> peek(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
... et utilisé confortablement avec Optional
:
return repository.findById(id)
.map(this.peek(logger.debug("Found user = {} with id = {}", u, id)))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
Il existe déjà des méthodes Optional::ifPresent
et Optional::isPresent
pour enregistrer le résultat. Mais vous voulez probablement quelque chose en ligne. La réponse à cette question est probablement un oubli.