Qual è il modo migliore per filtrare una raccolta Java?


Risposte:


699

Java 8 ( 2014 ) risolve questo problema usando stream e lambda in una riga di codice:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

Ecco un tutorial .

Utilizzare Collection#removeIfper modificare la raccolta in atto. (Nota: in questo caso, il predicato rimuoverà gli oggetti che soddisfano il predicato):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj consente di filtrare le raccolte senza scrivere loop o classi interne:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Riesci a immaginare qualcosa di più leggibile?

Disclaimer: sono un collaboratore di lambdaj


34
Bello ma le importazioni statiche offuscano quello che sta succedendo. Per riferimento, selezionare / avere / on sono importazioni statiche su ch.lambdaj.Lambda, maggiore di org.hamcrest.Matchers
MikePatel

11
LambdaJ è davvero sexy, ma vale la pena notare che implica un notevole sovraccarico (media 2.6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Doc Davluz,


7
Mi piace molto questo esempio di LamdaJ ... simile alle funzioni Lambda integrate .NET. E dove può bere una persona all'età di 16 anni? Dovremmo considerare l'aggiunta di un vincolo di localizzazione. : P
MAbraham,

3
rimuovi Se l'esempio dovrebbe esserepersons.removeIf(p -> p.getAge() <= 16);
vim

223

Supponendo che si stia utilizzando Java 1.5 e che non sia possibile aggiungere raccolte Google , farei qualcosa di molto simile a quello che hanno fatto i ragazzi di Google. Questa è una leggera variazione sui commenti di Jon.

Per prima cosa aggiungi questa interfaccia al tuo codebase.

public interface IPredicate<T> { boolean apply(T type); }

I suoi implementatori possono rispondere quando un determinato predicato è vero per un certo tipo. Ad esempio, se Tfosse Usere AuthorizedUserPredicate<User>implementa IPredicate<T>, quindi AuthorizedUserPredicate#applyrestituisce se il passatoUser è autorizzato.

Quindi, in alcune classi di utilità, potresti dire

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

Quindi, supponendo che tu abbia l'uso di quanto sopra potrebbe essere

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

Se le prestazioni sul controllo lineare sono preoccupanti, allora potrei voler avere un oggetto di dominio con la raccolta di destinazione. L'oggetto dominio che ha la raccolta di destinazione avrebbe una logica di filtro per i metodi che inizializzano, aggiungono e impostano la raccolta di destinazione.

AGGIORNARE:

Nella classe di utilità (diciamo Predicato), ho aggiunto un metodo select con un'opzione per il valore predefinito quando il predicato non restituisce il valore previsto e anche una proprietà statica per i parametri da utilizzare all'interno del nuovo IPredicate.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

L'esempio seguente cerca gli oggetti mancanti tra le raccolte:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

L'esempio seguente cerca un'istanza in una raccolta e restituisce il primo elemento della raccolta come valore predefinito quando l'istanza non viene trovata:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

AGGIORNAMENTO (dopo la versione Java 8):

Sono passati diversi anni da quando io (Alan) ho pubblicato questa risposta per la prima volta, e non riesco ancora a credere di raccogliere punti SO per questa risposta. Ad ogni modo, ora che Java 8 ha introdotto delle chiusure nella lingua, la mia risposta ora sarebbe considerevolmente diversa e più semplice. Con Java 8, non è necessaria una distinta classe di utilità statica. Quindi, se vuoi trovare il primo elemento che corrisponde al tuo predicato.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

L'API JDK 8 per optional ha la capacità di get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier)e orElseThrow(exceptionSupplier), così come altre funzioni 'monadici' come map, flatMapefilter .

Se si desidera semplicemente raccogliere tutti gli utenti che corrispondono al predicato, utilizzare il Collectorsper terminare il flusso nella raccolta desiderata.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Vedi qui per ulteriori esempi su come funzionano i flussi Java 8.


27
Sì, ma odio reinventare la ruota, ancora, ripetutamente. Preferirei trovare qualche libreria di utilità che fa quando voglio.
Kevin Wong,

2
Questo non è il modo migliore nel caso in cui non desideri la nuova collezione. Usa la metafora dell'iteratore di filtri, che può essere inserita in una nuova raccolta o potrebbe essere tutto ciò di cui hai bisogno.
Josh,

@Nestor: in una comprensione di Scala, il filtraggio sarebbe molto più semplice:val authorized = for (user <- users if user.isAuthorized) yield user
Alan,

Questo modifica la collezione originale o ne crea una nuova? Ho provato a utilizzare questo metodo e ho registrato entrambe le mie raccolte (quella originale e quella restituita dal metodo), sono uguali. @Alan
Rohan

1
@Rohan, questo non significa mutare la collezione originale. Si noti che la raccolta di risultati sopra è di nuova costruzione e il metodo di filtro si aggiunge alla raccolta di risultati solo se si applica il predicato.
Alan,

92

3
questo va bene, ma non è generico e modifica la raccolta in atto (non carina)
Kevin Wong,

2
Esistono altri metodi di filtro in CollectionUtils che non modificano la raccolta originale.
Skaffman,

42
In particolare, il metodo che non modifica la raccolta in atto è org.apache.commons.collections.CollectionUtils # select (Collection, Predicate)
Eero

5
In Commons Collections v4 ora utilizza Generics.
Justin Emery,

1
Questo metodo dovrebbe essere usato con cautela poiché si basa (almeno nell'implementazione di commons-collections-3.2.1) sul metodo iterator.remove () che è facoltativo per le raccolte, quindi invece di filtrare, diciamo, un array, potresti ottenere un UnsupportedOperationException.
user2417480,

67

Il modo "migliore" è una richiesta troppo ampia. È "il più corto"? "Più veloce"? "Leggibile"? Filtro in atto o in un'altra raccolta?

Il modo più semplice (ma non più leggibile) è di iterarlo e utilizzare il metodo Iterator.remove ():

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

Ora, per renderlo più leggibile, puoi inserirlo in un metodo di utilità. Quindi inventare un'interfaccia IPredicate, creare un'implementazione anonima di tale interfaccia e fare qualcosa del tipo:

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

dove filterInPlace () esegue l'iterazione della raccolta e chiama Predicate.keepIt () per sapere se l'istanza deve essere conservata nella raccolta.

Non vedo davvero una giustificazione per portare in una libreria di terze parti solo per questo compito.


6
Il mio voto vale per questo: funziona, senza librerie esterne. Non ho mai realizzato che l'istanza di un Iteratore potesse effettivamente essere utile rispetto all'utilizzo della sintassi for-each, o che potresti rimuovere elementi da un elenco senza ConcurrentModificationException o qualcosa del genere. :)
ZeroOne,

1
Penso che questo sia il modo migliore di usare la lib Java standard senza copiare. Per 1.8 ci sarebbe la stream()funzionalità, ma non tutti possono giocare con i giocattoli più recenti: P
Populus

Questo modifica anche la collezione originale? @ZeroOne
Rohan,

Sì, certo che lo fa, @Rohan. Provalo se non ci credi. ;)
ZeroOne

Ahah l'ho fatto! Ma voglio conservare la mia collezione originale. Puoi suggerire un modo per farlo senza aggiungere una libreria esterna? @ZeroOne
Rohan,

62

Prendi in considerazione le raccolte di Google per un framework di raccolte aggiornato che supporti i generici.

AGGIORNAMENTO : la libreria delle raccolte di Google è ora obsoleta. Dovresti usare invece l'ultima versione di Guava . Ha ancora le stesse estensioni al framework delle raccolte, incluso un meccanismo di filtraggio basato su un predicato.


sapevo della lib delle raccolte di Google. La versione che stavo usando non aveva Collezioni2. Ho aggiunto una nuova risposta a questa domanda che elenca il metodo specifico.
Kevin Wong,

7
Kevin, Iterables.filter () e Iterators.filter () ci sono stati fin dall'inizio e di solito sono tutto ciò di cui hai bisogno.
Kevin Bourrillion,

28

Attendi Java 8:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());

13
Ugh ... è così prolisso. Perché non potevano semplicemente fare: Elenco <Person> result = personList.filter (p -> p.age> 30);
Kevin Wong,

8
Per utilizzare il filtro direttamente su Collection è necessario utilizzare removeIf call: download.java.net/jdk8/docs/api/java/util/…
gavenkoa

6
@KevinWong "verbose" descrive praticamente l'intera lingua che penso. Almeno sono coerenti?
Rogue,

5
Perché non usare Collectors.toList () nell'ultima parte?
Nestor Hernandez Loli,

3
Ecco un link gavenkoa fornito che non 404. personList.removeIf(p -> p.age < 30);Meno dettagliato. Inoltre, ho sentito parlare di iniziare a implementare API che accettano e restituiscono Streams piuttosto che Collections perché Streams sono molto utili e veloci ma andare da / verso di loro è lento.
Captain Man,

11

Dalla prima versione di Java 8, potresti provare qualcosa del tipo:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

Ad esempio, se avevi un elenco di numeri interi e desideri filtrare i numeri che sono> 10 e quindi stampare quei numeri sulla console, potresti fare qualcosa del tipo:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);

11

Mi butto RxJava sul ring, che è disponibile anche su Android . RxJava potrebbe non essere sempre l'opzione migliore, ma ti darà maggiore flessibilità se desideri aggiungere più trasformazioni alla tua raccolta o gestire errori durante il filtraggio.

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

Produzione:

1
3
5

Maggiori dettagli su RxJava filtersono disponibili qui .


7

Il set up:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

L'utilizzo:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});

2
Bene, ma preferisco l'implementazione di Alan perché ottieni una copia della raccolta invece di alterarla. Inoltre, il codice di Alan è thread-safe mentre il tuo no.
marcospereira,

7

Che ne dici di Java semplice e diretto

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Semplice, leggibile e facile (e funziona su Android!) Ma se stai usando Java 8 puoi farlo in una sola riga:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

Si noti che toList () viene importato staticamente



7

Diamo un'occhiata a come filtrare un Elenco JDK incorporato e un Elenco modifiche usando le raccolte Eclipse .

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

Se si desidera filtrare i numeri inferiori a 3, ci si aspetterebbe i seguenti risultati.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

Ecco come è possibile filtrare utilizzando un lambda Java 8 come Predicate.

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));

Ecco come puoi filtrare usando una classe interna anonima come Predicate.

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));

Ecco alcune alternative al filtraggio degli elenchi JDK e delle mutableLists delle raccolte Eclipse utilizzando la fabbrica Predicati .

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Ecco una versione che non alloca un oggetto per il predicato, usando la factory Predicates2 invece con il selectWithmetodo che accetta a Predicate2.

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

A volte vuoi filtrare su una condizione negativa. Esiste un metodo speciale nelle raccolte Eclipse per quello chiamato reject.

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));

Il metodo partitionrestituirà due raccolte, contenenti gli elementi selezionati da e rifiutati da Predicate.

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

Nota: sono un committer per le raccolte Eclipse.


1
Come faresti un removeIfin un elenco o impostare per le primitive?
Vivek Rao,

L'API per removeIf è stata aggiunta alle raccolte primitive in EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
Donald Raab

5

Con il DSL ForEach puoi scrivere

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

Data una raccolta di [The, quick, brown, fox, jumps, over, the, lazy, dog] questo si traduce in [quick, brown, jumps, over, lazy], ovvero tutte le stringhe più lunghe di tre caratteri.

Tutti gli stili di iterazione supportati da ForEach DSL sono

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Per maggiori dettagli, consultare https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach


È abbastanza intelligente! Un sacco di lavoro per implementare una bella sintassi di Ruby-ish però! Il negativo è che il filtro non è una funzione di prima classe e quindi non può essere riutilizzato. Rotola sulle chiusure ...
oxbow_lakes,

Buon punto. Un modo per riutilizzare il corpo del ciclo consiste nel refactoring del ciclo in un metodo che accetta la query di selezione come parametro. Tuttavia, ciò non è di gran lunga pratico e potente come le chiusure reali.
Akuhn,


5

Poiché java 9 Collectors.filtering è abilitato:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

Quindi il filtro dovrebbe essere:

collection.stream().collect(Collectors.filtering(predicate, collector))

Esempio:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));

3

Questo, combinato con la mancanza di chiusure reali, è la mia più grande lamentela per Java. Onestamente, la maggior parte dei metodi sopra menzionati sono piuttosto facili da leggere e DAVVERO efficienti; tuttavia, dopo aver trascorso del tempo con .Net, Erlang, ecc ... la comprensione dell'elenco integrata a livello linguistico rende tutto molto più pulito. Senza aggiunte a livello linguistico, Java non può essere pulito come molte altre lingue in quest'area.

Se le prestazioni sono un grosso problema, le raccolte di Google sono la strada da percorrere (o scrivi la tua semplice utility predicato). La sintassi Lambdaj è più leggibile per alcune persone, ma non è altrettanto efficiente.

E poi c'è una biblioteca che ho scritto. Ignorerò qualsiasi domanda relativa alla sua efficienza (sì, è così male) ...... Sì, conosco la sua chiara riflessione, e no non la uso effettivamente, ma funziona:

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

O

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");

Link? Anche se la tua libreria è inefficiente o altrimenti inutilizzabile, potrebbe essere interessante vedere se la fonte è disponibile.
MatrixFrog,

Rendere pubblico il repository ( net-machine.com/indefero/p/jdclib/source/tree/master ). Sei interessato al pacchetto di espressioni. Il pacchetto di test ha un tester con esempio di utilizzo. Non ho mai lavorato molto sull'interfaccia di query di stringhe sopra citata (non mi andava di scrivere un vero parser), quindi l'interfaccia di query esplicita nel tester è la strada da percorrere.
jdc0589,

2

JFilter http://code.google.com/p/jfilter/ è più adatto alle tue esigenze.

JFilter è una libreria open source semplice e ad alte prestazioni per eseguire query sulla raccolta di bean Java.

Funzionalità chiave

  • Supporto delle proprietà di raccolta (java.util.Collection, java.util.Map e Array).
  • Supporto della raccolta all'interno della raccolta di qualsiasi profondità.
  • Supporto di domande interne.
  • Supporto di query con parametri.
  • Può filtrare 1 milione di record in pochi 100 ms.
  • Il filtro (query) viene fornito in un semplice formato json, è come le query Mangodb. Di seguito sono riportati alcuni esempi.
  • {"id": {"$ le": "10"}
    • dove la proprietà id oggetto è inferiore a uguale a 10.
  • {"id": {"$ in": ["0", "100"]}}
    • dove la proprietà id oggetto è 0 o 100.
  • { "LineItems": { "lineAmount": "1"}}
    • dove la proprietà collection lineItems di tipo con parametri ha lineAmount uguale a 1.
  • {"$ and": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
    • dove la proprietà id è 0 e la proprietà billingAddress.city è DEL.
  • {"lineItems": {"tasse": {"chiave": {"codice": "GST"}, "valore": {"$ gt": "1.01"}}}}
    • dove la proprietà collection lineItems di tipo con parametri che ha proprietà del tipo di mappa delle tasse di tipo con parametri ha codice uguale al valore GST maggiore di 1,01.
  • {'$ o': [{'code': '10'}, {'skus': {'$ e': [{'price': {'$ in': ['20', '40']} }, {'code': 'RedApple'}]}}]}
    • Seleziona tutti i prodotti in cui il codice prodotto è 10 o il prezzo sku in 20 e 40 e il codice sku è "RedApple".

1
Dovresti dichiarare che sei l'autore (come penso sia il caso).
assylias,

Sì, sono l'autore di questa biblioteca.
Kamran Ali Khan,

2

Ho scritto una classe Iterable estesa che supporta l'applicazione di algoritmi funzionali senza copiare il contenuto della raccolta.

Uso:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

Il codice sopra verrà effettivamente eseguito

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}


2

Alcune risposte davvero fantastiche qui. Io, vorrei mantenerlo il più semplice e leggibile possibile:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}

Basta implementare il giusto excludeItem per filtro. Finirai per avere filtri separati esattamente come i selezionatori nelle Collezioni ...
Lawrence,

1

La semplice soluzione pre-Java8:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

Sfortunatamente questa soluzione non è completamente generica, producendo un elenco piuttosto che il tipo di raccolta data. Inoltre, portare librerie o scrivere funzioni che racchiudono questo codice mi sembra eccessivo a meno che la condizione non sia complessa, ma puoi scrivere una funzione per la condizione.


1

https://code.google.com/p/joquery/

Supporta diverse possibilità,

Raccolta data,

Collection<Dto> testList = new ArrayList<>();

di tipo,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

Filtro

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

Anche,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Ordinamento (disponibile anche per Java 7)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Raggruppamento (disponibile anche per Java 7)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Joins (disponibile anche per Java 7)

Dato,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Può essere unito come,

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

espressioni

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);

1

La mia risposta si basa su quella di Kevin Wong, qui come one-liner che usa CollectionUtilsfrom spring e un'espressione lambda di Java 8 .

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Questo è conciso e leggibile come qualsiasi altra alternativa che abbia mai visto (senza usare librerie basate sull'aspetto)

Primavera CollectionUtils è disponibile dalla versione primavera 4.0.2.RELEASE, e ricordare è necessario JDK 1.8 e livello linguistico 8+.


1

Utilizzando java 8, in particolare lambda expression, puoi farlo semplicemente come nell'esempio seguente:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

dove per ogni raccolta productinterna myProducts, se prod.price>10, quindi aggiungere questo prodotto al nuovo elenco filtrato.


1

Avevo bisogno di filtrare un elenco in base ai valori già presenti nell'elenco. Ad esempio, rimuovere tutti i valori seguenti che è inferiore al valore corrente. {2 5 3 4 7 5} -> {2 5 7}. O ad esempio per rimuovere tutti i duplicati {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

Questa ape verrà utilizzata in questo modo.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});

0

Con Guava:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5

0

In Java 8, è possibile utilizzare direttamente questo metodo di filtro e quindi farlo.

 List<String> lines = Arrays.asList("java", "pramod", "example");

 List<String> result = lines.stream()              
         .filter(line -> !"pramod".equals(line))     
         .collect(Collectors.toList());              

 result.forEach(System.out::println); 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.