2010-04-05 6 views
7

In C++, posso usare find_if con un predicato per trovare un elemento in un contenitore. C'è qualcosa di simile in Java? Il metodo contains su raccolte utilizza uguali e non può essere parametrizzato.C'è qualcosa come find_if in Java?

+0

Il predicato è ciò che viene in mente chk http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/class-use/Predicate .html – Narayan

+1

Inoltre, dai un'occhiata a http://code.google.com/p/google-collections, in particolare le interfacce di predicati e funzioni. – gpampara

risposta

11

È possibile utilizzare Predicate da Google Collections. Ecco l'tutorial e un esempio da esso:

final Predicate<Car> expensiveCar = new Predicate<Car>() { 
    public boolean apply(Car car) { 
     return car.price > 50000; 
    } 
} 

List<Car> cars = Lists.newArrayList(); 
cars.add(new Car("Ford Taurus", 20000)); 
cars.add(new Car("Tesla", 90000)); 
cars.add(new Car("Toyota Camry", 25000)); 
cars.add(new Car("McClaren F1", 600000)); 

final List<Car> premiumCars = 
    Lists.immutableList(Iterables.filter(cars, expensiveCar)); 

Si può anche guardare a questa discussione: What is the best way to filter a Collection?

+0

'Iterables.find' (http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html#find%28java.lang.Iterable,%20com.google. common.base.Predicate% 29) fornirà solo il primo elemento corrispondente. –

+0

@Matthew Flaschen: sì, se abbiamo solo bisogno di ottenere almeno 1 elemento corrispondente, 'Iterables.find' sarebbe la soluzione migliore. – Roman

+0

Penso che tu stia utilizzando una vecchia versione preliminare di Google Collections! Se vuoi copiare il file iterabile filtrato in un elenco immutabile (invece di eseguirlo direttamente direttamente), usa ImmutableList.copyOf(). –

2

È possibile utilizzare CollectionUtils.select da Apache Commons.

Ad esempio, il seguente codice C++

bool isOdd (int i) { 
    return i % 2 != 0; 
    } 
    ... 
    vector<int> myvector; 
    vector<int>::iterator it; 

    myvector.push_back(10); 
    myvector.push_back(25); 
    myvector.push_back(40); 
    myvector.push_back(55); 

    it = find_if (myvector.begin(), myvector.end(), isOdd); 
    cout << "The first odd value is " << *it << endl; 

può essere scritta in Java come,

List<Integer> myList = Arrays.asList(10, 25, 40, 55); 
List<Integer> oddNums = (List<Integer>) CollectionUtils.select(myList, 
    new Predicate<Integer>() { 
    public boolean apply(Integer i) { 
     return i % 2 != 0; 
    } 
    } 
); 
System.out.println("The first odd value is "+oddNums.get(0)); 

Si prega di notare che, a differenza ad esempio C++, questo creerebbe un nuovo elenco degli elementi soddisfacendo il predicato specificato.

EDIT:

Come Matthew Flaschen ha suggerito in un commento qui sotto, CollectionUtils.find è ancora più vicino a quello che ti serve. Così, con find, il codice di cui sopra può essere riscritta come:

List<Integer> myList = Arrays.asList(10, 25, 40, 55); 
Integer firstOdd = (Integer) CollectionUtils.find(myList, 
    new Predicate<Integer>() { 
    public boolean apply(Integer i) { 
     return i % 2 == 1; 
    } 
    } 
); 
System.out.println("The first odd value is "+firstOdd); 
+0

CollectionUtils.find (http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html#find%28java.util.Collection,%20org.apache.commons.collections.Predicate% 29) è ancora più vicino; restituisce solo il primo elemento corrispondente. –

+0

@ Matthew: Grazie. Aggiornato la risposta per includerlo. – missingfaktor

+0

Non usare mai apache-collections a meno che non si sia già in java 1.4.2 o inferiore. – KitsuneYMG

0

Utilizzando lambdaj si può facilmente filtrare una collezione java in modo molto leggibile. Ad esempio la seguente dichiarazione:

select(persons, having(on(Person.class).getAge(), greaterThan(30))); 

seleziona tutte le persone nell'elenco con più di 30 anni.

1

Il problema è che l'utilizzo di un metodo come find_if dovrebbe rendere il codice più semplice da scrivere e più facile da leggere. Tuttavia, IMHO Java non si presta alla notazione funzionale e la maggior parte delle volte è più semplice e chiaro scrivere semplicemente un ciclo naturale. il codice è più breve e non richiede la conoscenza delle biblioteche che la maggior parte delle persone non usa. Se questa funzionalità è stata integrata e le chiusure supportate da Java (come , apparirà Java 7), l'utilizzo di predicati e metodi funzionali avrebbe più senso.

Una misura di complessità è contare il numero di simboli (contando le parentesi aperte/chiuse come una sola) Utilizzando questa misura di complessità, la maggior parte delle soluzioni basate su predicati ha più simboli e può essere più complessa e difficile da leggere per gli sviluppatori .

Nell'esempio fornito da @Roman, ci sono 15 simboli. Nell'esempio del ciclo, ci sono 10 simboli.

List<Car> premiumCars = new ArrayList(); 
for(Car car: cars) 
    if(car.price > 50000) 
     premiumCars.add(car); 

Nell'esempio di @Mario Fuscom, ci sono 9 simboli, nell'esempio seguente ci sono 9 simboli. Tuttavia, non sono richieste funzioni non standard e chiunque conosca Java può leggerlo/mantenerlo.

List peopleOver30 = new ArrayList(); 
for(Person person: people) 
    if(person.age > 30) 
     peopleOver30.add(person); 

Prendendo l'ultimo esempio da @Rahul G - Odio gli Unicorni, ci sono 13 simboli. Nell'esempio del ciclo, ci sono 8 simboli.

Integer firstOdd = null; 
for(int i: myList) 
    if(i % 2 == 1) { 
     firstOdd = i; 
     break; 
    } 

programmazione funzionale può rendere più senso per voi, perché questo è il tuo background di sviluppo, ma questo non significa che è il modo naturale o più semplice per esprimere questo in Java. Java 7 potrebbe cambiare questo ...

+0

Buona risposta Peter. Ho provato a utilizzare uno stile funzionale in Java e ho anche scoperto che rende il codice più complesso e più difficile da capire. –

Problemi correlati