Riferimento metodo istanza e parametri lambda

Ho difficoltà a capire la syntax per un riferimento al metodo, dove ci sono due parametri a e b , e il riferimento è a un metodo di a su b .

Ad esempio capisco come

 Arrays.sort(personArray, comparators::compareByName); 

è equivalente a

 Arrays.sort(personArray, (o1, o2) -> comparators.compareByName(o1, o2)); 

perché in quel caso i parametri lambda corrispondono ai parametri di chiamata del metodo (o1, o2) .

Comunque per questo lambda

 stream.sorted((o1, o2) -> o1.compareToIgnoreCase(o2)); 

il mio IDE mi dice che è equivalente a:

 stream.sorted(String::compareToIgnoreCase); 

e non sto trovando una regola per sostituire quella syntax: a.method(b) con un riferimento al metodo.

Ad esempio, cosa succede se ci sono tre o più parametri per il lambda? È legale? Il primo parametro diventa il metodo target e il rimanente diventa i parametri?

Penso che tu stia cercando la sezione JLS 15.13.3 , che include:

Se il form è ReferenceType :: [TypeArguments] Identifier , il corpo del metodo di invocazione ha l’effetto di un’espressione di ReferenceType :: [TypeArguments] Identifier del metodo per una dichiarazione in fase di compilazione che è la dichiarazione in fase di compilazione dell’espressione di riferimento del metodo. La valutazione run-time dell’espressione del richiamo del metodo è specificata in §15.12.4.3, §15.12.4.4 e §15.12.4.5, dove:

  • La modalità di chiamata è derivata dalla dichiarazione di compilazione come specificato in §15.12.3.

  • Se la dichiarazione in fase di compilazione è un metodo di istanza, il riferimento di destinazione è il primo parametro formale del metodo di chiamata. Altrimenti, non vi è alcun riferimento al target.

  • Se la dichiarazione in fase di compilazione è un metodo di istanza, gli argomenti dell’espressione di richiamo del metodo (se presenti) sono il secondo e i successivi parametri formali del metodo di chiamata. In caso contrario, gli argomenti dell’espressione di richiamo del metodo sono i parametri formali del metodo di chiamata.

Nota gli ultimi due proiettili, fondamentalmente.

Ad esempio, cosa succede se ci sono tre o più parametri per il lambda? È legale? Il primo parametro diventa il metodo target e il rimanente diventa i parametri?

Sì 🙂

Vorrei dare un paio di esempi qui, per coloro che trovano la documentazione Oracle un po ‘difficile da accettare. Immagina di avere bisogno di un riferimento a un’istanza di Comparator:

 .sorted(String::compareTo) 

String :: compareTo è identico a:

 (String a, String b) -> a.compareTo(b); 

Perché, come ha spiegato Jon, un riferimento al metodo verrà trasformato in un lambda che si attenderà 2 parametri. L’object arbitrario reale passato nel stream come primo argomento e un altro parametro (poiché Comparator si aspetta che int compare(T o1, T o2) ). Un altro caso:

 .map(Employee::getSalary) 

In questo caso la mappa si aspetta: Funzione. La funzione richiede l’implementazione di R apply(T var1) – un metodo con 1 argomento. In questo caso, l’unico parametro che verrà passato a lambda è l’object arbitrario effettivo: istanza su Employee.

Per riassumere, a seconda del contesto di tempo di compilazione, il riferimento al metodo di un object arbitrario sarà sempre “trasformato” in un lambda che si aspetta che l’object come primo parametro + qualsiasi numero di parametri che il metodo di destinazione richiede nello stesso ordine corrispondente.