2015-06-24 6 views
6

Diciamo che hoPosso filtrare un flusso <T> in base alla classe dell'elemento e ottenere un flusso <U> in un solo passaggio?

class Dog extends Animal {} 
class Cat extends Animal {} 

e ho una lista di animali Utilizzando Guava FluentIterable posso filtrare e convertire in un unico passaggio

List<Cat> cats = FluentIterable.from(animals) 
    .filter(Cat.class) 
    .toList(); 

Utilizzando Java8 ho bisogno di fare

List<Cat> cats = animals.stream() 
    .filter(c -> c instanceof Cat) 
    .map(c -> (Cat) c) 
    .collect(Collectors.toList()); 

Non c'è modo che io possa fare la mappa del filtro & in un solo passaggio, giusto?

+0

In C# è il '' metodo di estensione Enumerable.OfType , ma non so cosa sia in Java. –

+0

il magico 'flatMap()' .... ma non farlo :) – ZhongYu

+1

prova anche '.filter (Cat.class :: isInstance) .map (Cat.class :: cast)' - non c'è niente di meglio ovviamente. – ZhongYu

risposta

3

Il passaggio map non è necessario in fase di esecuzione (non fa semplicemente nulla), è necessario solo per aggirare il controllo del tipo durante la compilazione. In alternativa è possibile utilizzare sporco fusione incontrollata:

List<Cat> cats = ((Stream<Cat>) (Stream<?>) animals.stream().filter(
     c -> c instanceof Cat)).collect(Collectors.toList()); 

Purtroppo non c'è modo standard per fare questo in un'unica fase, ma è possibile utilizzare librerie di terze parti. Per esempio, nella mia biblioteca StreamEx c'è un metodo che selectsolves this problem:

List<Cat> cats = StreamEx.of(animals).select(Cat.class).toList(); 
+0

Non avevo capito che si trattava solo di una compilation ... –