Il vaut mieux exprimer ce comportement dans le code:
List<Integer> list= new ArrayList<>();
Stream.of(1,2,3).forEach(i -> list.add(1)); // COMPILES
Stream.of(1,2,3).forEach(i -> true); // DOES NOT COMPILE!
forEach(...)
accepte Consumer
, mais pourquoi le premier exemple est-il compilé si l'interface List a la signature suivante boolean add(E e)
? alors que la seconde donne:
type de retour incorrect dans l'expression lambda: le booléen ne peut pas être converti en vide
Bien que vous cherchiez peut-être juste
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
pourquoi le premier exemple est-il compilé si l'interface List a la suite signature booléenne ajouter (E e)
Principalement parce que le type de retour de la méthode est ignoré lors du premier appel. C'est ce qu'il se développe pour:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
D'autre part, l'autre représentation lambda ressemble plus à une Predicate
(qui est aussi une FunctionalInterface
) représentée comme renvoyant true
toujours à partir de sa méthode test
. Si vous essayez même de le représenter sous la forme d'une Consumer
, il se pourrait bien que
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
return true; // you can correlate easily now why this wouldn't compile
}
}); // DOES NOT COMPILE!
Pour ajouter au dimensionnement via un commentaire de Brian
Java vous permet d'appeler une méthode et d'ignorer la valeur renvoyée (une expression d'invocation de méthode sous forme d'instruction). Puisque nous permettons cela à l’invocation, nous l’autorisons également lors de l’adaptation d’une méthode à un interface fonctionnelle dont les arguments sont compatibles mais le fonctionnel l'interface est vide.
Edit: Pour le mettre dans ses propres mots aussi proches de la langue spécifiée :
Plus précisément,
list.add(x)
est une expression statement, et est donc compatible avec le vide.true
n'est pas une expression de déclaration, et donc pas vide compatible.forEach(Consumer)
nécessite un lambda compatible.
La règle spéciale de compatibilité avec vide (JLS) indique qu'un lambda qui renvoie vide peut accepter une instruction dont le retour est non nul. Dans ce cas, le retour est jeté. d'où cela compile.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
Pour Word un peu différemment en citant Java-8 dans Action book:
Si un lambda a pour expression une expression, son nom est compatible avec un descripteur de fonction qui retourne void (à condition que le paramètre list soit également compatible). Par exemple, les deux lignes suivantes sont légal même si la méthode add d’une liste renvoie un booléen et non vide comme prévu dans le contexte consommateur (T -> vide):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
En ce qui concerne le deuxième exemple, il s'agit de explicitement essayer de renvoyer un booléen où ce n'est pas prévu, donc impossible.
Stream.of(1,2,3).forEach(i -> true);
en d'autres termes:
Stream.of(1,2,3).forEach(i -> {return true;});
Comme vous le savez déjà, forEach
prend un consommateur. Par conséquent, toute tentative visant à renvoyer "explicitement" une boolean
devrait donner une erreur de compilation.
forEach()
en tant que Consommateur en tant que seul et unique paramètre. Par conséquent, vous devez donner une implémentation de la méthode accept()
qui renvoie void
. Ainsi, dans le deuxième exemple, vous implémentez une méthode avec l'assinature static boolean method(int)
donnée.