java


Why does Java 8 sometimes allow a Consumer to have a return value but not always? [duplicate]


The following Java code fails to compile:
#FunctionalInterface
private interface BiConsumer<A, B> {
void accept(A a, B b);
}
private static void takeBiConsumer(BiConsumer<String, String> bc) { }
public static void main(String[] args) {
takeBiConsumer((String s1, String s2) -> new String("hi")); // OK
takeBiConsumer((String s1, String s2) -> "hi"); // Error
}
The compiler reports:
Error:(31, 58) java: incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to void
The weird thing is that the line marked "OK" compiles fine, but the line marked "Error" fails. They seem essentially identical.
Your lambda needs to be congruent with BiConsumer<String, String>. If you refer to JLS #15.27.3 (Type of a Lambda):
A lambda expression is congruent with a function type if all of the following are true:
[...]
If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.
So the lambda must either be a statement expression or a void compatible block:
A constructor invocation is a statement expression so it compiles.
A string literal isn't a statement expression and is not void compatible (cf. the examples in 15.27.2) so it does not compile.
Basicly, new String("hi") is an executable piece of code that actually does something (it creates a new String and then returns it). The returned value can be ignored and new String("hi") can still be used in void-return lambda to create a new String.
However, "hi" is just a constant that doesn't do anything on it's own. The only reasonable thing to do with it in lambda body is to return it. But the lambda method would have to have return type String or Object, but it returns void, hence the String cannot be casted to void error.
The first case is ok because you are invoking a "special" method (a constructor) and you are no actually taking the created object. Just to make it more clear, I'll put the optional braces in your lambdas:
takeBiConsumer((String s1, String s2) -> {new String("hi");}); // OK
takeBiConsumer((String s1, String s2) -> {"hi"}); // Error
And more clear, I'll translate that to the older notation:
takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) {
public void accept(String s, String s2) {
new String("hi"); // OK
}
});
takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) {
public void accept(String s, String s2) {
"hi"; // Here, the compiler will attempt to add a "return"
// keyword before the "hi", but then it will fail
// with "compiler error ... bla bla ...
// java.lang.String cannot be converted to void"
}
});
In the first case you are executing a constructor, but you are NOT returning the created object, in the second case you are attempting to return a String value, but your method in your interface BiConsumer returns void, hence the compiler error.
The JLS specify that
If the function type's result is void, the lambda body is either a
statement expression (§14.8) or a void-compatible block.
Now let's see that in detail,
Since your takeBiConsumer method is of void type, the lambda receiving new String("hi") will interpret it as a block like
{
new String("hi");
}
which is valid in a void, hence the first case compile.
However, in the case where the lambda is -> "hi", a block such as
{
"hi";
}
is not valid syntax in java. Therefore the only thing to do with "hi" is to try and return it.
{
return "hi";
}
which is not valid in a void and explain the error message
incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to void
For a better understanding, note that if you change the type of takeBiConsumer to a String, -> "hi" will be valid as it will simply try to directly return the string.
Note that at first I tought the error was caused by the lambda being in a wrong invocation context, so I'll share this possibility with the community :
JLS 15.27
It is a compile-time error if a lambda expression occurs in a program
in someplace other than an assignment context (§5.2), an invocation
context (§5.3), or a casting context (§5.5).
However in our case, we are in an invocation context which is correct.

Related Links

getResource returning NullPointerException
Recursive method to print value of each array index in order
Hibernate build query from List<Criterion> with or operators and dynamic Restrictions
Roboelectric is giving me a java.lang.IllegalArgumentException: INTERNET permission is required
Mybatis mapper with interface instead of xml file
Error Message: Int cann't be converted to type
Querying Hive table with Spark DataFrames causes ClassNotFoundException in yarn-client mode
Error in Parameter index out of range (2 > number of parameters, which is 1)
Running a task within a custom task in Gradle
Java median. When I have an array with a pair number, the median I get isnt correct [duplicate]
Android Button ArrayList onClickListener doesn't work. Why?
Unexpected response code 415
Calculate elapsed time and cpu time of a parallel program
Codingbat java String 2 plusOut - “String index out of range - 1”
Encryption based on a Minecraft world. Is it possible?
Netty4 - TCP Server - basic testing using Camel

Categories

HOME
yii2
cookies
google-play
syntax
electron
relay
filtering
pivotal-cloud-foundry
portia
esper
gorm
node-pdfkit
msp430
quartz-scheduler
tostring
google-static-maps
invantive-sql
sms-gateway
excel-vba-mac
scichart
lldb
grails3
swiftlint
visjs
csrf-protection
tapestry
chromium-embedded
nhapi
web-api-testing
opentype
jspm
subdomains
nat
yadcf
grails-3.1
form-data
ios5
http-digest
bitbucket-pipelines
xcode-extension
hilbert-curve
angularjs-factory
awt
broadcastreceiver
powershell-dsc
nxlog
scorm
menuitem
komodoedit
atomicity
alphabet
veracode
libusb-win32
namecoin
mako
flutterwave
nbconvert
webdriverjs
chord-diagram
topbeat
time-and-attendance
jquery-filter
paypal-express
moveit
hover-over
bluegiga
photobucket
t4mvc
python-3.2
jqgrid-formatter
tarjans-algorithm
php-ci
notify
clicktag
oxwall
xc16
wordpress-theme-customize
android-radiobutton
sgen
fluentautomation
reactfx
picturefill
message-driven-bean
viadeo
terminal-services
pyhdf
geos
access-rights
dataadapter
padarn
lcs
drools-planner
boost-filesystem
php-parser
qt-jambi
hirefire
self-extracting
paster
gallio
revisions
getresponsestream
anti-piracy
defensive-programming
multiple-languages
windows-live-messenger

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App