studio reales proyectos programacion para introducción incluye guia fuente desarrollo código aplicaciones java java-stream collectors

reales - ¿Cómo convertir la Lista<V> en Mapa<K, Lista<V>>, con flujos de Java 8 y proveedores personalizados de Lista y Mapa?



manual programacion android (2)

Es fácil convertir la List<V> en el Map<K, List<V>> . Por ejemplo:

public Map<Integer, List<String>> getMap(List<String> strings) { return strings.stream() .collect(Collectors.groupingBy(String::length)); }

Pero quiero hacerlo con mis propios proveedores de List y Map .

Se me ha ocurrido esto:

public Map<Integer, List<String>> getMap(List<String> strings) { return strings.stream() .collect(Collectors.toMap( String::length, item -> {List<String> list = new ArrayList<>(); list.add(item); return list;}, (list1, list2) -> {list1.addAll(list2); return list1;}, HashMap::new)); }

Pregunta: ¿Existe una manera más fácil, menos verbosa o más eficiente de hacerlo? Por ejemplo, algo como esto (que no funciona):

return strings.stream() .collect(Collectors.toMap( String::length, ArrayList::new, HashMap::new));

¿Y qué pasa si solo necesito definir el proveedor de la List , pero no el proveedor del Map ?


Tuve una situación similar. Lo resolví como

Map<String, List<Object>> map = stringList.stream().collect(Collectors.toMap(str -> str, str -> populateList(str)));

Y populateList() es:

private List<Object> populateList(final String str) { ... .... List<Object> list = // dao.get(str); return list; }


Usted podría tener lo siguiente:

public Map<Integer, List<String>> getMap(List<String> strings) { return strings.stream().collect( Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new)) ); }

El groupingBy recopiladoresBy groupingBy se puede utilizar para especificar qué tipo de mapa se desea, pasándole un proveedor del mapa deseado para mapFactory . Luego, el colector en sentido descendente, que se utiliza para recopilar elementos agrupados en la misma clave, es toCollection(collectionFactory) , que permite recopilar en una colección obtenida del proveedor dado.

Esto asegura que el mapa devuelto sea un HashMap y que las listas, en cada valor, sean ArrayList . Tenga en cuenta que si desea devolver implementaciones específicas de mapas y recopilaciones, es probable que desee que el método también devuelva esos tipos específicos, de modo que pueda usar sus propiedades.

Si solo desea especificar un proveedor de colecciones y seguir groupingBy por mapa predeterminado, solo puede omitir el proveedor en el código anterior y usar la sobrecarga de dos argumentos :

public Map<Integer, List<String>> getMap(List<String> strings) { return strings.stream().collect( Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new)) ); }

Como nota al margen, podría tener un método genérico para eso:

public <K, V, C extends Collection<V>, M extends Map<K, C>> M getMap(List<V> list, Function<? super V, ? extends K> classifier, Supplier<M> mapSupplier, Supplier<C> collectionSupplier) { return list.stream().collect( Collectors.groupingBy(classifier, mapSupplier, Collectors.toCollection(collectionSupplier)) ); }

La ventaja de esta declaración es que ahora puede usarla para tener HashMap específico de ArrayList s como resultado, o LinkedHashMap de LinkedLists s, si la persona que llama lo desea:

HashMap<Integer, ArrayList<String>> m = getMap(Arrays.asList("foo", "bar", "toto"), String::length, HashMap::new, ArrayList::new); LinkedHashMap<Integer, LinkedList<String>> m2 = getMap(Arrays.asList("foo", "bar", "toto"), String::length, LinkedHashMap::new, LinkedList::new);

pero, en ese momento, puede ser más sencillo usar directamente la groupingBy por el código ...