Why does .forEach(val -> list.add()) compile whereas .forEach(val -> true) doesn't? [duplicate]
This question already has an answer here:
Why do Consumers accept lambdas with statement bodies but not expression bodies?
3 answers
Why does a Java method reference with return type match the Consumer interface?
2 answers
It's better to express this behavior in the 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(...)
accepts Consumer
, but why does the first example compile if List interface has following signature boolean add(E e)
? whereas the second yields:
bad return type in lambda expression: boolean cannot be converted to
void
java java-8 compiler-errors java-stream
marked as duplicate by Aomine
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 15 '18 at 20:20
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
This question already has an answer here:
Why do Consumers accept lambdas with statement bodies but not expression bodies?
3 answers
Why does a Java method reference with return type match the Consumer interface?
2 answers
It's better to express this behavior in the 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(...)
accepts Consumer
, but why does the first example compile if List interface has following signature boolean add(E e)
? whereas the second yields:
bad return type in lambda expression: boolean cannot be converted to
void
java java-8 compiler-errors java-stream
marked as duplicate by Aomine
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 15 '18 at 20:20
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
Hint:Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method (X -> Y
mapping)Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?
– Pshemo
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
@JörgWMittag The compilation error printsincompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is.Consumer.accept(T t)
should returnvoid
(docs.oracle.com/javase/8/docs/api/java/util/function/…)
– Leonid Dashko
Dec 15 '18 at 19:25
1
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07
add a comment |
This question already has an answer here:
Why do Consumers accept lambdas with statement bodies but not expression bodies?
3 answers
Why does a Java method reference with return type match the Consumer interface?
2 answers
It's better to express this behavior in the 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(...)
accepts Consumer
, but why does the first example compile if List interface has following signature boolean add(E e)
? whereas the second yields:
bad return type in lambda expression: boolean cannot be converted to
void
java java-8 compiler-errors java-stream
This question already has an answer here:
Why do Consumers accept lambdas with statement bodies but not expression bodies?
3 answers
Why does a Java method reference with return type match the Consumer interface?
2 answers
It's better to express this behavior in the 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(...)
accepts Consumer
, but why does the first example compile if List interface has following signature boolean add(E e)
? whereas the second yields:
bad return type in lambda expression: boolean cannot be converted to
void
This question already has an answer here:
Why do Consumers accept lambdas with statement bodies but not expression bodies?
3 answers
Why does a Java method reference with return type match the Consumer interface?
2 answers
java java-8 compiler-errors java-stream
java java-8 compiler-errors java-stream
edited Dec 15 '18 at 19:59
Aomine
41.6k74071
41.6k74071
asked Dec 15 '18 at 15:58
Leonid DashkoLeonid Dashko
726611
726611
marked as duplicate by Aomine
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 15 '18 at 20:20
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by Aomine
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 15 '18 at 20:20
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
Hint:Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method (X -> Y
mapping)Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?
– Pshemo
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
@JörgWMittag The compilation error printsincompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is.Consumer.accept(T t)
should returnvoid
(docs.oracle.com/javase/8/docs/api/java/util/function/…)
– Leonid Dashko
Dec 15 '18 at 19:25
1
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07
add a comment |
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
Hint:Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method (X -> Y
mapping)Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?
– Pshemo
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
@JörgWMittag The compilation error printsincompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is.Consumer.accept(T t)
should returnvoid
(docs.oracle.com/javase/8/docs/api/java/util/function/…)
– Leonid Dashko
Dec 15 '18 at 19:25
1
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
Hint:
Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method ( X -> Y
mapping) Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?– Pshemo
Dec 15 '18 at 16:19
Hint:
Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method ( X -> Y
mapping) Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?– Pshemo
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
@JörgWMittag The compilation error prints
incompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is. Consumer.accept(T t)
should return void
(docs.oracle.com/javase/8/docs/api/java/util/function/…)– Leonid Dashko
Dec 15 '18 at 19:25
@JörgWMittag The compilation error prints
incompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is. Consumer.accept(T t)
should return void
(docs.oracle.com/javase/8/docs/api/java/util/function/…)– Leonid Dashko
Dec 15 '18 at 19:25
1
1
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07
add a comment |
3 Answers
3
active
oldest
votes
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate
(which is also a FunctionalInterface
) represented as returning true
always from its test
method. If you even try to represent it as a Consumer
, it might just look like
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!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely,
list.add(x)
is a statement expression, and
therefore is void-compatible.true
is not a statement expression,
and therefore not void-compatible.forEach(Consumer)
requires a
void-compatible lambda.
3
More precisely,list.add(x)
is a statement expression, and therefore is void-compatible.true
is not a statement expression, and therefore not void-compatible.forEach(Consumer)
requires a void-compatible lambda.
– Brian Goetz
Dec 16 '18 at 21:33
add a comment |
forEach()
as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept()
which returns void
so on the second example you're implementing a method with the given assinature static boolean method(int)
.
6
Can you explain, whylist.add(1)
, an expression that evaluates totrue
is a correct implementation of aConsumer
, whereastrue
, an expression that evaluates totrue
, is an incorrect implementation?
– Jörg W Mittag
Dec 15 '18 at 16:15
2
Like other people said before if you expand the lambda with the{ }
you'll get an expression on first case and an invalid statement at second.
– chriptus13
Dec 15 '18 at 16:59
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
If you don't use the brackets it either is a value which gets translated to areturn
or a method call.
– chriptus13
Dec 15 '18 at 17:34
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body isvoid
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Javatrue;
is not a valid statement (contrast other languages).
– wchargin
Dec 15 '18 at 20:09
|
show 1 more comment
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach
takes a Consumer so attempting to "explicitly" return a boolean
should & will yield a compilation error.
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate
(which is also a FunctionalInterface
) represented as returning true
always from its test
method. If you even try to represent it as a Consumer
, it might just look like
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!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely,
list.add(x)
is a statement expression, and
therefore is void-compatible.true
is not a statement expression,
and therefore not void-compatible.forEach(Consumer)
requires a
void-compatible lambda.
3
More precisely,list.add(x)
is a statement expression, and therefore is void-compatible.true
is not a statement expression, and therefore not void-compatible.forEach(Consumer)
requires a void-compatible lambda.
– Brian Goetz
Dec 16 '18 at 21:33
add a comment |
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate
(which is also a FunctionalInterface
) represented as returning true
always from its test
method. If you even try to represent it as a Consumer
, it might just look like
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!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely,
list.add(x)
is a statement expression, and
therefore is void-compatible.true
is not a statement expression,
and therefore not void-compatible.forEach(Consumer)
requires a
void-compatible lambda.
3
More precisely,list.add(x)
is a statement expression, and therefore is void-compatible.true
is not a statement expression, and therefore not void-compatible.forEach(Consumer)
requires a void-compatible lambda.
– Brian Goetz
Dec 16 '18 at 21:33
add a comment |
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate
(which is also a FunctionalInterface
) represented as returning true
always from its test
method. If you even try to represent it as a Consumer
, it might just look like
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!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely,
list.add(x)
is a statement expression, and
therefore is void-compatible.true
is not a statement expression,
and therefore not void-compatible.forEach(Consumer)
requires a
void-compatible lambda.
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate
(which is also a FunctionalInterface
) represented as returning true
always from its test
method. If you even try to represent it as a Consumer
, it might just look like
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!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely,
list.add(x)
is a statement expression, and
therefore is void-compatible.true
is not a statement expression,
and therefore not void-compatible.forEach(Consumer)
requires a
void-compatible lambda.
edited Dec 17 '18 at 1:21
answered Dec 15 '18 at 16:21
nullpointernullpointer
44.4k1095183
44.4k1095183
3
More precisely,list.add(x)
is a statement expression, and therefore is void-compatible.true
is not a statement expression, and therefore not void-compatible.forEach(Consumer)
requires a void-compatible lambda.
– Brian Goetz
Dec 16 '18 at 21:33
add a comment |
3
More precisely,list.add(x)
is a statement expression, and therefore is void-compatible.true
is not a statement expression, and therefore not void-compatible.forEach(Consumer)
requires a void-compatible lambda.
– Brian Goetz
Dec 16 '18 at 21:33
3
3
More precisely,
list.add(x)
is a statement expression, and therefore is void-compatible. true
is not a statement expression, and therefore not void-compatible. forEach(Consumer)
requires a void-compatible lambda.– Brian Goetz
Dec 16 '18 at 21:33
More precisely,
list.add(x)
is a statement expression, and therefore is void-compatible. true
is not a statement expression, and therefore not void-compatible. forEach(Consumer)
requires a void-compatible lambda.– Brian Goetz
Dec 16 '18 at 21:33
add a comment |
forEach()
as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept()
which returns void
so on the second example you're implementing a method with the given assinature static boolean method(int)
.
6
Can you explain, whylist.add(1)
, an expression that evaluates totrue
is a correct implementation of aConsumer
, whereastrue
, an expression that evaluates totrue
, is an incorrect implementation?
– Jörg W Mittag
Dec 15 '18 at 16:15
2
Like other people said before if you expand the lambda with the{ }
you'll get an expression on first case and an invalid statement at second.
– chriptus13
Dec 15 '18 at 16:59
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
If you don't use the brackets it either is a value which gets translated to areturn
or a method call.
– chriptus13
Dec 15 '18 at 17:34
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body isvoid
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Javatrue;
is not a valid statement (contrast other languages).
– wchargin
Dec 15 '18 at 20:09
|
show 1 more comment
forEach()
as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept()
which returns void
so on the second example you're implementing a method with the given assinature static boolean method(int)
.
6
Can you explain, whylist.add(1)
, an expression that evaluates totrue
is a correct implementation of aConsumer
, whereastrue
, an expression that evaluates totrue
, is an incorrect implementation?
– Jörg W Mittag
Dec 15 '18 at 16:15
2
Like other people said before if you expand the lambda with the{ }
you'll get an expression on first case and an invalid statement at second.
– chriptus13
Dec 15 '18 at 16:59
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
If you don't use the brackets it either is a value which gets translated to areturn
or a method call.
– chriptus13
Dec 15 '18 at 17:34
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body isvoid
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Javatrue;
is not a valid statement (contrast other languages).
– wchargin
Dec 15 '18 at 20:09
|
show 1 more comment
forEach()
as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept()
which returns void
so on the second example you're implementing a method with the given assinature static boolean method(int)
.
forEach()
as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept()
which returns void
so on the second example you're implementing a method with the given assinature static boolean method(int)
.
answered Dec 15 '18 at 16:09
chriptus13chriptus13
381212
381212
6
Can you explain, whylist.add(1)
, an expression that evaluates totrue
is a correct implementation of aConsumer
, whereastrue
, an expression that evaluates totrue
, is an incorrect implementation?
– Jörg W Mittag
Dec 15 '18 at 16:15
2
Like other people said before if you expand the lambda with the{ }
you'll get an expression on first case and an invalid statement at second.
– chriptus13
Dec 15 '18 at 16:59
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
If you don't use the brackets it either is a value which gets translated to areturn
or a method call.
– chriptus13
Dec 15 '18 at 17:34
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body isvoid
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Javatrue;
is not a valid statement (contrast other languages).
– wchargin
Dec 15 '18 at 20:09
|
show 1 more comment
6
Can you explain, whylist.add(1)
, an expression that evaluates totrue
is a correct implementation of aConsumer
, whereastrue
, an expression that evaluates totrue
, is an incorrect implementation?
– Jörg W Mittag
Dec 15 '18 at 16:15
2
Like other people said before if you expand the lambda with the{ }
you'll get an expression on first case and an invalid statement at second.
– chriptus13
Dec 15 '18 at 16:59
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
If you don't use the brackets it either is a value which gets translated to areturn
or a method call.
– chriptus13
Dec 15 '18 at 17:34
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body isvoid
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Javatrue;
is not a valid statement (contrast other languages).
– wchargin
Dec 15 '18 at 20:09
6
6
Can you explain, why
list.add(1)
, an expression that evaluates to true
is a correct implementation of a Consumer
, whereas true
, an expression that evaluates to true
, is an incorrect implementation?– Jörg W Mittag
Dec 15 '18 at 16:15
Can you explain, why
list.add(1)
, an expression that evaluates to true
is a correct implementation of a Consumer
, whereas true
, an expression that evaluates to true
, is an incorrect implementation?– Jörg W Mittag
Dec 15 '18 at 16:15
2
2
Like other people said before if you expand the lambda with the
{ }
you'll get an expression on first case and an invalid statement at second.– chriptus13
Dec 15 '18 at 16:59
Like other people said before if you expand the lambda with the
{ }
you'll get an expression on first case and an invalid statement at second.– chriptus13
Dec 15 '18 at 16:59
2
2
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
As was pointed out in another answer, the reason is void-compatibility, not syntax.
– Jörg W Mittag
Dec 15 '18 at 17:33
2
2
If you don't use the brackets it either is a value which gets translated to a
return
or a method call.– chriptus13
Dec 15 '18 at 17:34
If you don't use the brackets it either is a value which gets translated to a
return
or a method call.– chriptus13
Dec 15 '18 at 17:34
3
3
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body is
void
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Java true;
is not a valid statement (contrast other languages).– wchargin
Dec 15 '18 at 20:09
@JörgWMittag: That’s the right question to ask. The answer is that a lambda body is
void
-compatible only if “the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement)” (§15.27.3), and in Java true;
is not a valid statement (contrast other languages).– wchargin
Dec 15 '18 at 20:09
|
show 1 more comment
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach
takes a Consumer so attempting to "explicitly" return a boolean
should & will yield a compilation error.
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
add a comment |
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach
takes a Consumer so attempting to "explicitly" return a boolean
should & will yield a compilation error.
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
add a comment |
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach
takes a Consumer so attempting to "explicitly" return a boolean
should & will yield a compilation error.
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach
takes a Consumer so attempting to "explicitly" return a boolean
should & will yield a compilation error.
edited Dec 15 '18 at 17:34
answered Dec 15 '18 at 16:29
AomineAomine
41.6k74071
41.6k74071
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
add a comment |
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
1
1
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
I believe that this is the answer, but I am still having trouble seeing it clearly. The lambda spec explicitly distinguishes between lambdas with expression bodies and lambdas with block bodies, whereas void-compatibility rule talks specifically about lambdas with a block body and does not mention expression-bodied lambdas. However, both examples in the question are expression-bodies lambdas. I cannot point my finger on exactly that part of the spec that says this. Your quote from Java in Action seems to interpret the spec the same way as you, and I believe that interpretation is correct, I …
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
… just can't find where it is actually supported by the spec.
– Jörg W Mittag
Dec 15 '18 at 17:37
add a comment |
What are you trying to achieve with the second statement?
– Nicholas K
Dec 15 '18 at 16:06
Hint:
Stream.of(1,2,3).forEach(i -> {return list.add(1);})
also doesn't compile. Hint2: What method (X -> Y
mapping)Consumer<T>
represents (take a look at abstract method it contains, what type of parameter(s) it accepts and what is its return type)?– Pshemo
Dec 15 '18 at 16:19
Instead of simply stating "does not compile", it would be much better if you could show the precise error message you are getting. In particular, at least one answer is operating under the assumption that you are getting a syntax error (although in that case, "does not parse" would be more correct than "does not compile"), but I don't think a syntax error is the problem.
– Jörg W Mittag
Dec 15 '18 at 16:19
@JörgWMittag The compilation error prints
incompatible types: bad return type in lambda expression missing return value
. @Pshemo before I started this thread I checked what is the signature is.Consumer.accept(T t)
should returnvoid
(docs.oracle.com/javase/8/docs/api/java/util/function/…)– Leonid Dashko
Dec 15 '18 at 19:25
1
@LeonidDashko when I ran this on IntelliJ IDEA I got the error I've included in the post. However, since it's not word for word the same as what you've just mentioned, please consider updating the post with the exact information.
– Aomine
Dec 15 '18 at 20:07