20 Kasım 2019 Çarşamba

Collectors toMap ve groupingBy Farkları

Giriş
Klasik açıklaması şöyle. Yani klasik kullanımda toMap() One-To-One ilişkilerde, groupingBy() ise One-To-Many ilişkilerde kullanılır.
To collect into a Map that contains a single value by key (Map<MyKey,MyObject>), use Collectors.toMap().

To collect into a Map that contains multiple values by key (Map<MyKey, List<MyObject>>), use Collectors.groupingBy().
Ancak her iki metodun da kesiştiği noktalar var.

toMap metodu Aynı Key Değelerine İzin Vermez
Elimizde şöyle bir kod olsun. Eğer duplicate A nesneleri varsa IllegalStateException fırlatılır
Map<A, Collection<B>> resultMap = listofA.stream()
    .collect(Collectors.toMap(Function.identity(), repo::getListofB);
Bu durumda merge function ile kullanmak gerekir. Şöyle yaparız. Bu durumda groupingBy() ile aynı işlevi elde deriz.
Map<A, Collection<B>> resultMap = listofA.stream()
  .collect(Collectors.toMap(Function.identity(), repo::getListofB, 
     (a, b) -> {
       a.addAll(b);
       return a;
}));
groupingBy flatMapping ile kullanılırsa Aynı Key Değerlerini Birleştirebilir
Şöyle yaparız.
Map<A, List<B>> aToBmap = listofA.stream()
  .collect(Collectors.groupingBy(Function.identity(),
    Collectors.flatMapping(a -> getListofB(a).stream(), 
    Collectors.toList())));
Diğer
Her iki örnekte de one-to-many ilişki vardı. Eğer many-to-many ilişkimiz varsa başka bir şey yapmak gerekir. Örneğin elimizde bir yıllara göre kataloglar listesi olsun. Her katalog kendi içinde ayakkabılar listesine sahip olsun. Bir ayakkabının hangi yıllarda kullanıldığını indekslemek için şöyle yaparız
List<Catalog> catalogs = ...;
Map<String,List<Catalog> shoeNameToCatalogMap = new LinkedHashMap<>();
for (Catalog catalog : catalogs){
  catalog.getShoeNames()
    .foreach(shoeName  -> shoeNameToCatalogMap
                         .computeIfAbsent(shoeName, x -> new ArrayList<>()).add(catalog);
}

Hiç yorum yok:

Yorum Gönder