¿Trabajando sobre las propiedades de los objetos en una lista?

Con el siguiente código:

public class MyObject { String myProperty; public MyObject(String propertyValue) { myProperty=propertyValue; } } 

y

 public class Main { public static void main(String[] args) { ArrayList<MyObject> objects = new ArrayList<MyObject>(); objects.add(new MyObject("first")); objects.add(new MyObject("second")); objects.add(new MyObject("third")); // Now do Task A and Task B } } 

Ahora estoy buscando la mejor manera de hacer lo siguiente:

Tarea A: Encuentra todos los objetos donde myProperty es igual a "second". Hay algo como

 ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ? 

Tarea B: Extrae los diferentes valores myProperty de la lista, lo que significa que quiero obtener una matriz que incluye ("first", "second", "third") ¿Hay algo como

 ArrayList propertyValues = objects.getPropertyValues(myProperty) ? 

Sé que la tarea A y B se puede resolver mediante el bucle a través de la ArrayList, pero me pregunto si hay una manera mejor / ya algo incorporado en Eclipse? Gracias por cualquier pista 🙂

Tenga en cuenta que no quiero utilizar bibliotecas externas (actualmente estoy desarrollando en android y quiero mantener mi aplicación pequeña).

    Si necesita el primero (Tarea A), puede indicar que ArrayList no es la estructura de datos óptima que debería usar. Este tipo de acceso debe hacer que considere el uso de un Map o un MultiMap (implementado en Apache Commons Collections ).

    Pero … Si realmente necesitas este tipo de cosas. Varias bibliotecas son útiles.

    Recientemente popular es la guayaba . Otro es LambdaJ que parece más especializado:

     // Task A filter(having(on(MyObject.class).getPropertyValue(), equalTo("second")), objects); // Task B convert(objects, new PropertyExtractor("propertyValue")); // or even extract(objects, on(MyObject.class).getPropertyValue()); 

    (No tuve la oportunidad de compilar / ejecutar el código que escribí, así que por favor no sea demasiado estricto al respecto)

    … pero permite entonces decir que estoy buscando la mejor manera en java sin bibliotecas externas?

    En ese caso, mejor enfoque es escribir bucles.

    Es posible construir una solución basada en el acceso reflexivo a los campos con nombre, pero el código no es simple y ciertamente no funciona.

    … así que supongo que me están matando por mis compañeros de equipo si introdujo una biblioteca externa que utilizo sólo por una cosa pequeña.

    Sus compañeros de trabajo estarían inclinados a matarlo por hacer esto usando la reflexión también. La mejor manera de asegurar su supervivencia con sus gónadas aún unidas (:-)) es escribir los bucles.

    Eclipse no te ayudaría directamente en tal tarea – solo puede ayudar a crear el programa – no crea en sí mismo.

    Si agregar una nueva biblioteca al proyecto no es una opción, puede escribir su propia solución genérica. Sin embargo, te sugiero que busques en la adición de alguna biblioteca común como Guava o Apache Commons como se sugirió antes.

    Las dos tareas que está intentando lograr se pueden describir más generalmente como filtrado y mapeo (también conocido como "seleccionar, proyectar"). El filtrado se puede generalizar usando un predicado – una función simple que devolverá si el objeto debe ser incluido en la nueva colección. La asignación se puede lograr mediante una función genérica que toma un objeto de origen (en su caso, MyObject), y devuelve un objeto de otro tipo (en su caso, String).

    Esas operaciones de conjunto (colección) son soportadas más fácilmente por lenguajes, algunos de ellos compilados a la JVM, como python (jython), groovy y scala. Pero supongo que no es una opción usar un idioma diferente para el proyecto.

    Así que voy a demostrar cómo se puede lograr en Java, aunque la sintaxis es un poco más clunkier, ya que vamos a utilizar clases anónimas para el predicado y el convertidor.

    Hay un ejemplo simple de un filtro de bricolaje en ¿Cuál es la mejor manera de filtrar una colección de Java? , Así que lo usaré en el ejemplo.

    Las dos interfaces que necesitamos:

     public interface Convertor<FROM, TO> { TO convert(FROM from); } public interface Predicate<T> { boolean apply(T type); } 

    Y la "biblioteca" real:

     import java.util.ArrayList; import java.util.Collection; public class CollectionUtils { public static <FROM, TO> Collection<TO> select(Collection<FROM> from, Convertor<FROM, TO> convertor) { Collection<TO> result = new ArrayList<TO>(); for (FROM fromItem: from) { result.add(convertor.convert(fromItem)); } return result; } public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) { Collection<T> result = new ArrayList<T>(); for (T element: target) { if (predicate.apply(element)) { result.add(element); } } return result; } } 

    Ahora podemos lograr fácilmente las dos tareas:

     import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; public class Main { public static void main(String[] args) { ArrayList<MyObject> objects = new ArrayList<MyObject>(); objects.add(new MyObject("first")); objects.add(new MyObject("second")); objects.add(new MyObject("third")); // Now do Task A and Task B // Task A: Filter Collection<MyObject> filtered = CollectionUtils.filter(objects, new Predicate<MyObject>() { @Override public boolean apply(MyObject myObject) { return myObject.myProperty.equals("second"); } }); for (MyObject myObject: filtered) {System.out.println(myObject.myProperty);} System.out.println(); // TASK B: Map/Select Collection<String> transforemd = CollectionUtils.select(objects, new Convertor<MyObject, String>() { @Override public String convert(MyObject from) { return from.myProperty; } }); for (String str: transforemd) {System.out.println(str);} } } 

    Sería muy simple ahora cambiar el predicado para filtrar otros objetos, o crear diferentes cadenas, o incluso otros tipos en lugar de script: sólo cambiar las funciones apply () y convert ()! (Oh bien, y algunos consejos genéricos :)).

    Exención de responsabilidad: El código no está completamente probado, acaba de ser presentado para la demostración, y puede tener algunos otros problemas (como la asignación de ArrayList para nuevas colecciones). Esta es la razón por la que suele ser mejor utilizar bien probado y depurado bibliotecas de terceros!

    Es cierto que lo siguiente es un poco de publicidad de mi trabajo, pero se ajusta exactamente a su problema.

    En primer lugar, alguien tiene que hacer el trabajo. O lo hace usted mismo, es decir, escribir los bucles necesarios a ti mismo, o si alguna biblioteca hacer el trabajo para usted.

    No sé acerca de las otras libs sugeridas aquí, pero si te interesa echar un vistazo a http://tbull.org/projects/util4j/ , se trata de una lib pequeña que escribí yo mismo y la licencia le permite tomar la Cosas que necesita del código fuente e incluirlo en su propia fuente.

    En este enfoque, específicamente diseñados Grepper s y Mapper s se utilizan, por lo que no hay necesidad de reflexión. De hecho, es muy similar a lo que Amitay Dobo ya ha publicado, pero este lib proporciona modos más versátiles de operación, incluyendo la lectura de los elementos de entrada de Iterator s y lazy grepping / mapping.

    Tarea A: Encuentra todos los objetos donde myProperty es igual a "second". Hay algo como

     ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ? 

    Esto se haría como

     import org.tbull.util.Collections; import org.tbull.util.Grepper; private static class PropertyGrepper implements Grepper<MyObject> { public final String property; public PropertyGrepper(String property) { this.property = property; } public @Override boolean grep(MyObject element) { return element.myProperty.equals(property); } } List<MyObject> filteredObjects = Collections.grep(new PropertyGrepper("second"), objects); 

    Tarea B: Extrae los diferentes valores myProperty de la lista, lo que significa que quiero obtener una matriz que incluye ("first", "second", "third") ¿Hay algo como

     ArrayList propertyValues = objects.getPropertyValues(myProperty) ? 
     import org.tbull.util.Collections; import org.tbull.util.Mapper; private static class PropertyExtractor implements Mapper<MyObject, String> { public @Override String map(MyObject element) { return element.myProperty; } } List<String> propertyValues = Collections.map(new PropertyExtractor(), objects); 

    Exención de responsabilidad: Este código no ha sido probado. myProperty tiene que ser accesible para que esto funcione, sea public o sea proporcionado por una función getter.

    Por supuesto, puede hacer uso de clases internas anónimas para la brevedad o implementar el Grepper / Mapper públicamente para su reutilización.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.