2015-10-21 6 views
12

In Java 1.8, la seguente espressione lambda conforme ad entrambe le interfacce funzionali Runnable e Callable:scegliendo tra i metodi di overload se il parametro attuale è un lambda

() -> { 
    throw new RuntimeException("FIXME"); 
} 

Tuttavia, se presento a un utilizzando un metodo a un solo argomento e ignora il valore restituito (ovvero non sono disponibili informazioni sull'inferenza di tipo), ExecutorService#submit(Callable) viene scelto in fase di compilazione, a meno che non esprima esplicitamente il cast di lambda a Runnable.

Come fa il compilatore scegliere tra i metodi di overload nel caso di cui sopra, a condizione che Runnable e Callable non condividono alcuna gerarchia comune e più specifica tipo regola non si applica qui?

+0

@Makoto Questo è esattamente il motivo per cui il sovraccarico ** avviene ** qui. – biziclop

+0

@biziclop: Non sono sicuro del motivo per cui ho perso il controllo e sovraccarico per un secondo. Deve essere il tempo. – Makoto

+0

Stranamente il mio codice di esempio sceglie il sovraccarico 'Runnable'. – biziclop

risposta

7

I credo perché Callable dichiara un tipo di reso e Runnable no.

Dalla sezione JLS 15.12.2.5, viene scelto il sovraccarico con il tipo più specifico, se ne esiste uno in modo univoco più specifico. Questo è quello che dice di più specifici tipi di interfaccia funzionali:

Un funzionale tipo di interfaccia S è più specifico di un funzionale tipo di interfaccia T per l'espressione e se T non è un sottotipo di S e una delle seguenti è true (dove U1 ... Uk e R1 sono i tipi di parametri e il tipo di ritorno del tipo di funzione dell'acquisizione di S, e V1 ... Vk e R2 sono i tipi di parametri e il tipo di ritorno del tipo di funzione di T):

Se e è un'espressione lambda esplicitamente digitato (§15.27.1), quindi una delle seguenti condizioni:

  • R2 è vuoto ...

T è Runnable, S è Callable, Callable è più specifica perché il tipo di ritorno non è vuoto, quindi Callable viene scelto

risoluzione sovraccarico Metodo è molto complicato, quindi ci può essere un po 'che ho perso, ma penso che sia per questo che sceglie Callable

+1

Penso che dovresti aggiungere che l'espressione lambda nell'OP è considerata tipizzata esplicitamente perché ha zero parametri. – RealSkeptic

+0

@RealSkeptic: Né 'call' né' run' richiedono argomenti, quindi come farebbe uno più tipizzato dell'altra? – Makoto

+0

Le cose sembrano essere un po 'più complicate. Se non si lancia l'eccezione, viene selezionato 'Runnable'. – biziclop

4

Anche se la risposta di @thecoop è corretta, c'è un altro aspec t del meccanismo lambda degno di nota.

Lambdas con corpi di blocco rientrano in due categorie: void-compatible and value-compatible.

Il lambda nella domanda è entrambi, perché non può completare normalmente (a causa dell'eccezione incondizionata) e tutte le dichiarazioni return in entrambi sono prive di valore e restituiscono un valore, visto che non c'è nessuna dichiarazione return.

La maggior parte dei lambdas tuttavia sono uno o l'altro. E se il lambda è solo void-compatible, il lambda sarà compatibile solo con Runnable.

Ciò che è leggermente controintuitivo (ma logicamente corretto) è che anche se il lambda nella domanda non restituisce mai un valore, è classificato come "restituisce sempre un valore quando c'è un return".

+0

"tutte le dichiarazioni di ritorno in là sono senza valore" è un'affermazione priva di senso quando non ci sono. Potrei anche dire "tutte le dichiarazioni di ritorno in là forniscono un valore". Questo non sta dimostrando nulla. E non è classificato come "sempre restituendo un valore", ma essendo * compatibile con il valore * che significa semplicemente, come è stato detto, che è * compatibile * con una funzione dichiarata per restituire un valore, non che restituisce un valore valore. – Holger

+0

@Holger 'Un blocco lambda body è compatibile con void se ogni dichiarazione di ritorno nel blocco ha il modulo return; .' Non incolparmi, questa è la definizione. E secondo questa definizione, qualcosa senza "return" in esso è considerato vuoto-compatibile. – biziclop

+0

@Holger E compatibile con il valore: 'Un blocco lambda body è compatibile con i valori se non può completare normalmente (§14.21) e ogni dichiarazione di ritorno nel blocco ha il modulo return Expression ;.'Di nuovo, qualcosa che genera sempre un'eccezione sarà classificata come compatibile al valore poiché ogni istruzione return nel blocco ha la forma' return Expression; '(e non può completare normalmente neanche) – biziclop

Problemi correlati