Why doesn't for-each method in java not throw an exception when a Function type argument is passed instead of Consumer? [duplicate]

烈酒焚心 提交于 2019-12-10 19:44:53

问题


Why doesn't forEach method in java not show a compiler error when a Function type argument is passed instead of Consumer? Here both of the lines are returning a boolean value for every element in the stream but only 2nd line gets a compilation error? Is there any other property of lambda expression for such scenario?

Here's my code:

Stream.of(1,2,3,4).forEach(a->a.equals(1));//line 1

Stream.of(1,2,3,4).forEach(a->{return a.equals(1);});//line 2

回答1:


Regarding why the first line works: there's an explanation in the specification:

Generally speaking, a lambda of the form () -> expr, where expr is a statement expression, is interpreted as either () -> { return expr; } or () -> { expr; }, depending on the target type.

The above comes with the following example (good coincidence, this is very similar to your example):

// Consumer has a void result
java.util.function.Consumer<String> c = s -> list.add(s);

This simply means that the compiler ignores the return type for the expression, as though your code were simply this (which is valid for a void method):

Stream.of(1, 2, 3, 4).forEach(a -> {
     a.equals(1);
});

And regarding the second line, the spec says:

A block lambda body is void-compatible if every return statement in the block has the form return;.

In your case, though, {return a.equals(1);} does not meet this rule. Void methods don't return a value.

An easy way to understand this is to consider that the compiler applies method body validation rules (such that the body must be compatible with the declaration public void accept(T t)) - as mentioned in the tutorial




回答2:


In the first line you provided a valid Consumer which takes an argument int a. This is what Stream.forEach expects. The fact, that the consumer will additionaly return a value doesn't matter. The returned value will not be evaluated, it will be discarded.

The second line contains a statement which returns a boolean. As this statement has a return value, it doesn't comply with the method of Consumer which takes an argument but is declared void. Thus this gives the compile-time error: Void methods cannot return a value

JLS 15.27.2 says:

A block lambda body is void-compatible if every return statement in the block has the form return;.

Thus the method returns without an explicit return value.

Regarding the return statement JLS 14.17. says:

A return statement with no Expression must be contained in one of the following, or a compile-time error occurs:

  • A method that is declared, using the keyword void, not to return a value (§8.4.5)

Applying this to the second line results in the following code:

Stream.of(1, 2, 3, 4).forEach(a -> { a.equals(1); return; });

Further notes:
By returning the value of equals in the second line this statement doesn't become a Function. It's still just a statement.

An exception will not be thrown as an exception can only be thrown on runtime. Since the code doesn't compile, it cannot be executed. As specified in the JLS a compile-time error is issued.




回答3:


In fact, in the first line you have Consumer as returned value is ignored. But in the second line you return result explicitly so expression became type of Function.



来源:https://stackoverflow.com/questions/52474643/why-doesnt-for-each-method-in-java-not-throw-an-exception-when-a-function-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!