In Ihrem ersten Beispiel
consumerIntFunctionTest(data -> {
Arrays.sort(data);
}, int[]::new);
der Lambda-Ausdruck einen void
-kompatible Block hat, die ohne die Notwendigkeit, durch die Struktur des Ausdrucks identifiziert werden kann, die tatsächlichen Arten zu lösen.
Im Gegensatz dazu ist in dem Beispiel
consumerIntFunctionTest(Arrays::sort, int[]::new);
Verfahren Referenz hat aufgelöst werden, um herauszufinden, ob es entweder übereinstimmt, eine void
Funktion (Consumer
) oder einen Wert zurückgegeben Funktion (Function
). Das gleiche gilt für den vereinfachte Lambda-Ausdruck
consumerIntFunctionTest(data -> Arrays.sort(data), int[]::new);
der beide sein könnte, void
- kompatibel oder wert- kompatibel, auf der aufgelösten Zielmethode abhängig.
Das Problem besteht darin, dass das Auflösen der Methode Kenntnisse über die erforderliche Signatur erfordert, die über die Zieltypisierung bestimmt werden sollte, aber der Zieltyp ist erst bekannt, wenn die Typparameter der generischen Methode bekannt sind. Während in der Theorie beide gleichzeitig bestimmt werden konnten, wurde der (immer noch sehr unangenehme) Prozess in der Spezifikation dahingehend vereinfacht, dass die Überladungsauflösung zuerst durchgeführt wird und die Typinferenz zuletzt angewendet wird (siehe JLS §15.12.2). Daher können die Informationen, die die Typrückschlüsse liefern könnten, nicht zum Lösen der Überladungsauflösung verwendet werden.
Aber beachten Sie, dass der erste in 15.12.2.1. Identify Potentially Applicable Methods beschriebenen Schritt enthält:
An expression is potentially compatible with a target type according to the following rules:
A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:
The arity of the target type's function type is the same as the arity of the lambda expression.
If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).
A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, there exists at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following is true:
The method reference expression has the form ReferenceType :: [TypeArguments] Identifier and at least one potentially applicable method is i) static and supports arity n, or ii) not static and supports arity n-1.
The method reference expression has some other form and at least one potentially applicable method is not static.
…
The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface target types. In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after overload resolution.
So Ihr in erstem Beispiel eines des Verfahrens wird durch das Lambdas der Form, während im Fall eines Verfahrens Referenz oder einen Lambda-Ausdrucks aussortiert aus eines einzigen Aufrufausdrucks erleiden beide potentiell anwendbaren Methoden diesen ersten Auswahlprozess und ergeben einen "mehrdeutigen" Fehler, bevor die Typinferenz eintreten kann, um das Finden einer Zielmethode zu unterstützen, um festzustellen, ob es sich um eine void
oder Rückgabewertmethode handelt.
Beachten Sie, dass wie x->{ foo(); }
mit einem Lambda-Ausdruck explizit void
-kompatible zu machen, Sie x->(foo())
verwenden können, einen Lambda-Ausdruck explizit Wert-kompatibel zu machen.
Sie verrückt weiter this answer erklärt lesen, dass diese Beschränkung des kombinierten Typinferenz und Auflösung überladene Methode eine bewusste (aber nicht leicht) Entscheidung war.
Der Ort in der JLS, wo dies definiert werden sollte, ist [15.27.3] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27. 3). (Habe es nicht im Detail angeschaut). – Jesper
Warum denken Sie, dass 'Funktion' nicht übereinstimmt? '?' könnte 'Void' auch sein, also stimmt es überein. –
tomse
@tomse 'Void' als Rückgabetyp hat nichts mit' void' als Methodentyp zu tun, das 'Void' ist nur ein Objekt. – skiwi