2014-12-19 13 views
5

La collezione di Scala fornisce un metodo chiamato collect che unisce filter e map in un unico metodo. È particolarmente utile quando si filtra una raccolta Object per produrre un sottoinsieme di quella raccolta contenente solo un tipo particolare.Esiste un metodo Java Stream equivalente alle raccolte di Scala "collect"?

Esiste qualcosa del genere con lo streaming di Java 8?

+1

Suppongo che tu sappia già che puoi fare la cosa giusta concatenando le chiamate 'map',' filter' e 'collect'. Quindi qual è lo scopo della tua richiesta di farlo in una chiamata al metodo? Perché quel "sente" come essere più efficiente? – Holger

+0

@Holger Lega la pre-condizione alla funzione di mappatura, il che aiuta a rendere chiara una _si_ una pre-condizione all'altra, inoltre rende impossibile rompere il codice cambiando l'ordine delle chiamate al metodo. –

+3

In realtà, è l'opposto. Nessuno può distinguere dalla firma di un singolo metodo che contiene una funzione di mappatura e un predicato che viene applicato per primo. Al contrario, con l'API 'Stream', tutti comprendono la differenza tra' map (...) .filter (...) .collect (...) 'e' .filter (...) .map (...) .collect (...) '. Ed è anche in grado di dedurre il significato di altre combinazioni come 'map (...) .filter (...) .map (...) .collect (...)' ... – Holger

risposta

7

Avendo una combinazione di filter e map in un solo passo non è utile in Java dato il suo sistema di tipi. Per esempio. non esiste un tale tipo di PartialFunction.

La cosa più vicina è flatMap:

List<Object> list=Arrays.asList(0, "foo", 0L, 42.0, true, "false"); 
List<String> sList = list.stream() 
    .flatMap(o-> o instanceof String? Stream.of((String)o): Stream.empty()) 
    .collect(Collectors.toList()); 
System.out.println(sList); 

ma l'espressività di

.flatMap(o-> o instanceof String? Stream.of((String)o): Stream.empty()) 

non è che più grande rispetto al

.filter(o -> o instanceof String).map(o -> (String)o) 

Naturalmente, è possibile creare un metodo di supporto incapsulare questi passaggi in un'unica operazione indissolubile:

static <T> Stream<T> onlyType(Stream<?> s, Class<T> type) { 
    return s.filter(type::isInstance).map(type::cast); 
} 

quindi è possibile utilizzarlo come

List<String> sList=onlyType(list.stream(), String.class).collect(Collectors.toList()); 
0

Sto cercando di fornire la risposta della tua domanda, come ho letto da qualche parte -

<R,A> R collect(Collector<? super T,A,R> collector) 

R - il tipo del risultato A - il tipo di accumulo intermedio del collettore collezionista - il collettore che descrive il riduzione Resi - il risultato della riduzione

Esegue un'operazione di riduzione mutabile sugli elementi di questo flusso utilizzando un servizio di raccolta. Un Collector racchiude le funzioni utilizzate come argomenti da raccogliere (Fornitore, BiConsumer, BiConsumer), consentendo il riutilizzo delle strategie di raccolta e la composizione delle operazioni di raccolta come il raggruppamento a più livelli o il partizionamento. Se il flusso è parallelo e il servizio di raccolta è simultaneo e il flusso non è ordinato o il raccoglitore non è ordinato, verrà eseguita una riduzione simultanea (consultare Collector per i dettagli sulla riduzione simultanea.)

Questo è un terminale operazione.

Quando eseguiti in parallelo, è possibile creare istanze multiple, risultati intermedi, popolati e uniti in modo da mantenere l'isolamento delle strutture di dati mutabili. Pertanto, anche se eseguito in parallelo con strutture dati prive di thread (come ArrayList), non è necessaria alcuna sincronizzazione aggiuntiva per una riduzione parallela.

Di seguito si accumulano stringhe in un ArrayList:

List<String> asList = stringStream.collect(Collectors.toList()); 

Di seguito sarà classificare oggetti Person per stato e città, a cascata due Collezionisti insieme:

Map<String, Map<String, List<Person>>> peopleByStateAndCity 
    = personStream.collect(Collectors.groupingBy(Person::getState, 
                Collectors.groupingBy(Person::getCity))); 
+0

Non sto parlando del metodo 'collect' di Java 8 di' Stream'. Sto parlando del metodo 'collect' di Scala e sto chiedendo un equivalente in Java 8. –

0

Per quanto mi riguarda posso dire da l'interfaccia Stream e alcune delle librerie di supporto, non esiste una singola operazione che esegue entrambi e produce un'uscita Stream (basata sulla mia lettura breve g del metodo Scala collect).

È necessario applicare entrambe le funzioni a un Stream per ottenere l'output desiderato Stream che può quindi essere raccolto o qualsiasi altra funzione che si desidera applicare ad esso.

collection.stream() 
    .filter(predicateFunction) 
    .map(mappingFunction) 
    .collect(Collectors.toList()) 
+1

Quella * è * una singola operazione, ma quell'operazione viene preparata usando invocazioni di metodi concatenati che stanno solo aumentando la flessibilità dell'API. – Holger

0

quanto ho capito la documentazione Scala, collect filtri a seconda che la funzione è presente, e si applica la funzione di ogni oggetto di qualificazione. Una classe Java ha una definizione fissa, quindi un test del genere non avrebbe molto senso. L'analogo più vicino sarebbe testando per un'interfaccia e richiamando il suo metodo (funzione) in più fasi:

stream.filter(e -> e instanceof SomeInterface).map(SomeInterface.class::cast).map(AnotherClass::convertSomeInterfaceToSomethingElse) 
0

Prova come questo

tList.stream().map[E](func).collect(Collectors.toList[E]) 

Il tlist è un tipo di voi nell'elenco sorgente, ed E è un tipo che si desidera returned.If il tipo di origine è uguale al tipo restituito, [E] non è necessario in mapE, sembra alla funzione map in scala il tipo restituito è object.

Problemi correlati