2010-04-05 16 views
7

En C++, puedo usar find_if con un predicado para encontrar un elemento en un contenedor. ¿Hay algo así en Java? El método contains en colecciones usa iguales y no se puede parametrizar.¿Hay algo así como find_if en Java?

+0

El predicado es lo que le viene a la mente chk http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/class-use/Predicate .html – Narayan

+1

Además, eche un vistazo a http://code.google.com/p/google-collections, especialmente las interfaces de predicado y función. – gpampara

Respuesta

11

Puede usar Predicate desde Google Collections. Aquí está el y un ejemplo de ello tutorial:

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)); 

Usted también puede buscar en este tema: 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) proporcionará solo el primer elemento coincidente. –

+0

@Matthew Flaschen: sí, si solo necesitamos obtener al menos 1 artículo correspondiente, entonces 'Iterables.find' sería la mejor solución. – Roman

+0

¡Creo que está utilizando una instantánea previa a la publicación muy antigua de Google Collections! Si desea copiar el elemento iterativo filtrado en una lista inmutable (en lugar de solo hacer un bucle directo), use ImmutableList.copyOf(). –

2

Puede utilizar CollectionUtils.select de Apache Commons.

Por ejemplo, el siguiente código 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; 

puede escribirse en Java como,

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)); 

Tenga en cuenta que, al contrario que en el ejemplo C++, esto crearía una nueva lista de los elementos satisfaciendo el predicado especificado.

EDIT:

Como Mateo Flaschen ha sugerido en un comentario más abajo, CollectionUtils.find es aún más cerca de lo que necesita. Por lo tanto, la find, el código anterior se puede reescribir como:

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) está aún más cerca; devuelve solo el primer elemento coincidente. –

+0

@Matthew: Gracias. Se actualizó la respuesta para incluir eso. – missingfaktor

+0

Nunca use apache-collections a menos que ya esté en Java 1.4.2 o inferior. – KitsuneYMG

0

Mediante el uso de lambdaj puede filtrar fácilmente una colección de Java de una manera muy fácil de leer. Por ejemplo, la siguiente instrucción:

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

selecciona a todas las personas en su lista que tienen más de 30 años.

1

El problema es que usar un método como find_if debería hacer que el código sea más simple de escribir y más fácil de leer. Sin embargo, IMHO Java no se presta a la notación funcional y la mayoría de las veces es más claro y simple escribir un bucle natural. es decir, el código es más corto y no requiere el conocimiento de las bibliotecas que la mayoría de la gente no usa. Si esta funcionalidad fue incorporada y Cierres admitidos por Java (como parece que Java 7 lo hará), entonces el uso de predicados y métodos funcionales tendría más sentido.

Una medida de la complejidad es contar el número de símbolos (contando los paréntesis abrir/cerrar como uno) Usando esta medida de complejidad, la mayoría de las soluciones basadas en predicados tienen más símbolos y posiblemente sean más complejas y difíciles de leer/mantener .

En el ejemplo dado por @Roman, hay 15 símbolos. En el ejemplo de bucle, hay 10 símbolos.

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

En el ejemplo de @Mario Fuscom, hay 9 símbolos, en el siguiente ejemplo hay 9 símbolos. Sin embargo, no se requieren funciones no estándar y cualquiera que conozca Java puede leerlo/mantenerlo.

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

Tomando el último ejemplo de @Rahul G - Odio los unicornios, hay 13 símbolos. En el ejemplo de bucle, hay 8 símbolos.

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

La programación funcional puede tener más sentido para usted, porque esa es su fondo de desarrollo, pero esto no quiere decir que es la forma natural o simple de expresar esto en Java. Java 7 puede cambiar esto ....

+0

Buena respuesta Peter. Intenté usar un estilo funcional dentro de Java y también descubrí que hace que el código sea más complejo y MÁS difícil de entender. –

Cuestiones relacionadas