16 Eylül 2019 Pazartesi

Collector.of metodu

Giriş
Şu satırı dahil ederiz
import static java.util.stream.Collector.of;
Collector nesnesi oluşturmak için iki tane yöntem var.
1. Collectors.xyz () metodlarını kullanmak
2. Collector.of() metodunu kullanmak

Collector.of metodu Niye Lazım?
Normalde stream().map(...).collect(Collectors.xyz()) şeklinde kullanırız. Eğer map() metodunu da Collectior içine yedirmek istersek Custom collector yazmak gerekir. of() metodu Custom Collector yazmak içindir.

Custom Collector yazmak için kullanılır.

of metodu - supplier + accumulator + combiner
İlk parametre Supplier, ikinci parametre Accumulator, üçüncü parametre Combiner nesneleridir. Dördüncü parametre Finisher veya Collector.Characteristics olabilir. Combiner paralel çalışmada iki tane sonucu birleştirmek için kullanılır.

Örnek
Şöyle yaparız.
Collector<Foo, MyResult, MyResult> MyCollector = Collector.of(
  () -> Foo::new,
  (a, p) -> { //a accumulation Type , p reduction işlemine giren nesne
    ...
  }, (r1, r2) -> { //r1 combiner r2 yeni accumulator
    ...;
});
Bu Collector şöyle kullanılır.
Map<Date, MyResult> results = stream().collect
  (groupingBy (Foo::getDate, MyCollector));
Örnek
Bir dizi nesne hakkında istatistiki bilgi toplamak isteyelim. Şu sql ile aynıdır.
Select sum(paidAmount), count(paidAmount), classificationName,
From tableA
Group by classificationName;
Sonuç şöyledir.
100, 2, classname1 
50, 1, classname2
150, 3, classname3
Elimizde şöyle bir kod olsun.
class Statistics {
  int count;
  BigDecimal sum;

  Statistics(Bucket bucket) {
    count = 1;
    sum = bucket.getPaidAmount();
  }
  Statistics() {
    count = 0;
    sum = BigDecimal.ZERO;
  }

  void add(Bucket b) {
    count++;
    sum = sum.add(b.getPaidAmount());
  }

  Statistics merge(Statistics another) {
    count += another.count;
    sum = sum.add(another.sum);
    return this;
  }
}
Şöyle yaparız.
Map<String, Statistics> map = lineItemList.stream()
    .collect(Collectors.groupingBy(Bucket::getBucketName,
        Collector.of(Statistics::new, Statistics::add, Statistics::merge)));
of metodu - supplier + accumulator + combiner + Flags
Paralel çalışan stream'lerin gerçekten paralel olarak toplanmasını sağlar.
Örnek
Şöyle yaparız.
Collector.of(
  () -> {
    System.out.printf("%s supplying\n", Thread.currentThread().getName());
    return Collections.synchronizedList(new ArrayList<>());
  },
(l, o) -> {
  System.out.printf("%s accumulating %s to %s\n", Thread.currentThread().getName(), o, l);
  l.add(o);
},
(l1, l2) -> {
  System.out.printf("%s combining %s & %s\n", Thread.currentThread().getName(), l1, l2);
  l1.addAll(l2);
  return l1;
},
Characteristics.CONCURRENT,
Characteristics.UNORDERED
)
of metodu - supplier + accumulator + combiner + finisher
finisher en son sonucu örneğin List nesnesini bir başka şey dönüştürmek içindir.
Örnek
Şöyle yaparız
return Collector.of(
  // First we specify that we want to add
  // each element from the stream to an ArrayList.
  () -> new ArrayList<String>(),
  // Next we add each String value to the list
  // and turn it into an uppercase value.
  (list, value) -> list.add(value.toUpperCase()),
  // Next we get two lists we need to combine,
  // so we add the values of the second list
  // to the first list.
  (first, second) -> { first.addAll(second); return first; },
  // Finally (and optionally) we turn the
  // ArrayList into an unmodfiable List.
  list -> Collections.unmodifiableList(list));
}
Örnek
Şöyle yaparız.
List<String> result = IntStream.of(1, 2, 3, 4, 5, 12, 13, 14, 19)
  .boxed()
  .collect(Collector.of(
    () -> {
      List<List<Integer>> list = new ArrayList<>();
      list.add(new ArrayList<>());
      return list;
    },
    (list, x) -> {
      List<Integer> inner = list.get(list.size() - 1);
        if (inner.size() == 0) {
          inner.add(x);
        } else {
          int lastElement = inner.get(inner.size() - 1);
          if (lastElement == x - 1) {
            inner.add(x);
          } else {
            List<Integer> oneMore = new ArrayList<>();
            oneMore.add(x);
            list.add(oneMore);
          }
        }
      },
      (left, right) -> {
        throw new IllegalArgumentException("No parallel!");
      },
      list -> {
      
        return list.stream()
          .map(inner -> {
            if (inner.size() > 1) {
              return inner.get(0) + "-" + inner.get(inner.size() - 1);
            }
            return "" + inner.get(0);
            }).collect(Collectors.toList());
}));

Hiç yorum yok:

Yorum Gönder