2015-08-21 2 views
15

Durante la lettura del codice sorgente Stream interfaccia ho trovato questo metodo di firma:generico delimitata jolly di tipo di ingresso funzione

<R> Stream<R> map(Function<? super T, ? extends R> mapper); 

mi chiedo perché il tipo di ingresso di mapper è ? super T mentre il tipo di uscita è ? extends R, perché non usare ? extends per entrambi?

+2

la differenza tra super e extends è stata risolta qui: http://stackoverflow.com/questions/1368166/what-is-a-difference-between-super-e-e-extends-e – gapvision

+0

Conosco la differenza , ma mi chiedo perché lo abbiano fatto? – toandv

+0

Se non ti dispiace la notazione diversa, ecco un discorso reale che lo spiega https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote-Domenity –

risposta

10

Esiste una regola generale che è stata menzionata per la prima volta da Joshua Bloch nel suo Effective Java book che si trova come PECS.

  • Produttore PE estende
  • CS consumatori Super

Questa funzione produce un risultato (? extends R) da ciò che ha ricevuto (? super T).

La documentazione di java.util.Function è un pò chiaro che:

rappresenta una funzione che accetta un argomento e produce un risultato.

12

A causa di PECS :) - Produttore Estende, Super Consumer

Produttore Estende - Se avete bisogno di un elenco per la produzione di T valori (che si desidera leggere Ts dalla lista), è necessario dichiarare con ? extends T Super

consumatori - Se avete bisogno di un elenco di consumare T valori (si vuole scrivere Ts nella lista), è necessario dichiararla con ? super T

+4

Questa risposta, mentre si dice fatti corretti, non risponde direttamente alla domanda. Forse aggiungere una frase o due per dire come si riferisce al metodo Stream di cui sopra? –

19

consideri si desidera mappare un CharSequence ad un altro CharSequence (quindi T = R = CharSequence). Quali funzioni funzioneranno per te?

Function<Object, String> fn1 = Object::toString; 

È buono per te? Sì, perché può richiedere qualsiasiCharSequence (che è anche Object) e convertirlo in String (che è anche CharSequence).

Function<CharSequence, StringBuilder> fn2 = StringBuilder::new; 

È buono per te? Sì, perché può richiedere qualsiasiCharSequence e convertirlo in StringBuilder (che è anche CharSequence).

Function<String, String> fn3 = String::trim; 

È buono per te? No, perché non può prendere CharSequence, solo alcuni di essi.

Così si può vedere che il primo argomento di tipo deve essere CharSequence o qualsiasi superclasse, ma il secondo deve essere CharSequence o qualsiasi sottoclasse.