이 Java 8 람다가 컴파일에 실패하는 이유는 무엇입니까?
다음 Java 코드는 컴파일에 실패합니다.
@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
}
컴파일러는 다음을보고합니다.
Error:(31, 58) java: incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to void
이상한 점은 "OK"로 표시된 줄은 잘 컴파일되지만 "Error"로 표시된 줄은 실패한다는 것입니다. 본질적으로 동일 해 보입니다.
람다는와 일치해야합니다 BiConsumer<String, String>
. JLS # 15.27.3 (Lambda 유형) 을 참조하는 경우 :
다음이 모두 참인 경우 람다 식은 함수 유형과 일치합니다.
- [...]
- 함수 형식의 결과가 void이면 람다 본문은 문 식 (§14.8) 또는 void 호환 블록입니다.
따라서 람다는 명령문 표현식이거나 void 호환 블록이어야합니다.
- 생성자 호출은 명령문 표현식 이므로 컴파일됩니다.
- 문자열 리터럴은 명령문 표현식이 아니며 무효 호환이되지 않으므로 ( 15.27.2의 예제 참조 ) 컴파일되지 않습니다.
기본적으로 new String("hi")
는 실제로 무언가를 수행하는 실행 가능한 코드 조각입니다 (새 문자열을 생성 한 다음 반환합니다). 반환 된 값은 무시할 수 있으며 new String("hi")
새 문자열을 만들기 위해 void-return 람다에서 계속 사용할 수 있습니다.
그러나은 "hi"
자체적으로 아무것도하지 않는 상수 일뿐입니다. 람다 본문에서 그것으로 할 수있는 유일한 합리적인 일은 그것을 반환 하는 것입니다. 그러나 람다 메서드는 반환 유형 String
또는 을 가져야 하지만를 Object
반환 void
하므로 String cannot be casted to void
오류가 발생합니다.
첫 번째 경우는 "특별한"메서드 (생성자)를 호출하고 실제로 생성 된 객체를 사용하지 않기 때문에 괜찮습니다. 더 명확하게하기 위해 람다에 선택적 중괄호를 넣겠습니다.
takeBiConsumer((String s1, String s2) -> {new String("hi");}); // OK
takeBiConsumer((String s1, String s2) -> {"hi"}); // Error
그리고 더 명확하게, 나는 그것을 이전 표기법으로 번역 할 것입니다.
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"
}
});
첫 번째 경우 생성자를 실행하지만 생성 된 객체를 반환하지 않고 두 번째 경우에는 String 값을 반환하려고하지만 인터페이스의 메서드 BiConsumer
가 void를 반환하므로 컴파일러 오류가 발생합니다.
JLS는 다음을 지정합니다.
함수 형식의 결과가 void이면 람다 본문은 문 식 (§14.8) 또는 void 호환 블록입니다.
이제 자세히 살펴 보겠습니다.
귀하의 takeBiConsumer
메서드가 void 유형이므로 람다 수신 new String("hi")
은이를 다음과 같은 블록으로 해석합니다.
{
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 :
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.
참고URL : https://stackoverflow.com/questions/29262002/why-does-this-java-8-lambda-fail-to-compile
'developer tip' 카테고리의 다른 글
Google Play에서 언어를 변경하려면 어떻게하나요? (0) | 2020.09.25 |
---|---|
여러 선물을 기다리는 방법 (0) | 2020.09.25 |
WPF에서 GridViewColumn 데이터를 자동 크기 조정하고 오른쪽 정렬하는 방법은 무엇입니까? (0) | 2020.09.24 |
Xcode-모든 파일에서 텍스트 검색 (0) | 2020.09.24 |
jQuery의 extend 메소드에 해당하는 JavaScript (0) | 2020.09.24 |