Giriş
İmzası şöyle.
Sonuç olarak kullanılacak container'ı döner.
Accumulator
Açıklaması şöyle. Yani container'a nesne ekler
Açıklaması şöyle. Eğer stream paralel kullanılıyorsa, iki tane sonuç container'ını birleştirir.
Açıklaması şöyle.
Örnek - ArrayList
Şöyle yaparız.
Şöyle yaparız.
Elimizde şöyle bir kod olsun
Şöyle yaparız. Burada Array içindeki string'lerin unique olduğu varsayılıyor.
Örnek - Averager
Şöyle bir sınıfımız olsun.
İmzası şöyle.
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
SupplierSonuç olarak kullanılacak container'ı döner.
Accumulator
Açıklaması şöyle. Yani container'a nesne ekler
accumulator - an associative, non-interfering, stateless function that must fold an element into a result container.Combiner Ne İşe Yarar
Açıklaması şöyle. Eğer stream paralel kullanılıyorsa, iki tane sonuç container'ını birleştirir.
Combiner yerine kendimiz yazmak istersek, lambda kullanabiliriz ya da sınıfımızın bir metodunu çağırabiliriz. Bu metod paralelleştirme varsa işe yarar. Açıklaması şöyle. Yani iki thread'in çıktısını birleştirmek için kullanılır.combiner - an associative, non-interfering, stateless function that accepts two partial result containers and merges them, which must be compatible with the accumulator function. The combiner function must fold the elements from the second result container into the first result container.
The first argument is a supplier that supplies an empty array list for adding collected stuff into. The second argument is a biconsumer that consumes each element of the array. The third argument is there only to provide parallelism support. This enables it to collect the elements into multiple array lists at the same time, and it asks you for a way to connect all these array lists together at the end.Combiner'ın devreye girdiği ve girmediğini görmek için şöyle yaparız.
String resultParallel = list.parallelStream().collect(
StringBuilder::new,
(builder, elem) -> builder.append(" ").append(elem),
(left, right) -> left.append(" ").append(right)).toString();
String result = list.stream().collect(
StringBuilder::new,
(builder, elem) -> builder.append(" ").append(elem),
(left, right) -> left.append(" ").append(right)).toString();
System.out.println("ResultParallel: ->" + resultParallel + "<-"); // -> 1 2 3 4<-
System.out.println("Result: ->" + result + "<-"); // -> 1 2 3 4<-
Combiner ve Accumulator aynı şekilde yani aynı sonucu dönmeliAçıklaması şöyle.
What this is saying is that it should not matter whether the elements are collected by "accumulating" or "combining" or some combination of the two. But in your code, the accumulator and the combiner concatenate using a different separator. They are not "compatible" in the sense required by the javadoc.Elimizde şöyle bir kod olsun. Combiner ve Accumulator aynı sonucu dönmedikleri için serial ve paralel koşmalarda farklı sonuç elde ederiz. Paralel koşmadan fazladan space karakterleri vardır. Çünkü accumulator nesnesine iki tane StringBuilder gelir ve her birinin başında space karakteri vardır.
String resultParallel = list.parallelStream().collect(
StringBuilder::new,
(builder, elem) -> builder.append(" ").append(elem),
(left, right) -> left.append(" ").append(right)).toString();
String result = list.stream().collect(
StringBuilder::new,
(builder, elem) -> builder.append(" ").append(elem),
(left, right) -> left.append(" ").append(right)).toString();
System.out.println("ResultParallel: ->" + resultParallel + "<-"); // -> 1 2 3 4<-
System.out.println("Result: ->" + result + "<-"); // -> 1 2 3 4<-
Kullanım ÖrnekleriÖrnek - ArrayList
Şöyle yaparız.
ArrayList<Integer> collected = Stream.of(1,2,3)
.collect(
ArrayList::new,
ArrayList::add,
ArrayList::addAll);
System.out.println(collected);
Örnek - ListŞöyle yaparız.
Path path = ...;
List<String> lines = Files.lines(path)
.collect(
ArrayList::new,
new BiConsumer<ArrayList<String>, String>() {
@Override
public void accept(ArrayList<String> lines, String line) {
...
}
},
ArrayList::addAll
);
Örnek - HashMapElimizde şöyle bir kod olsun
static class Foo {
private final int id;
private final String s;
public Foo(int id, String s) {
super();
this.id = id;
this.s = s;
}
public int getId() {
return id;
}
public String getS() {
return s;
}
@Override
public String toString() {
return "" + id;
}
}
Şöyle yaparızHashMap<String, Foo> result = Arrays.asList(new Foo(1, "a"), new Foo(2, "b"))
.stream()
.collect(HashMap::new,
(map, foo) -> map.put(foo.getS(), foo),
HashMap::putAll);
System.out.println(result); // {a=1, b=2}
Ancak eğer Foo'nun s alanı unique değilse şöyle yaparızHashMap<String, List<Foo>> result = Arrays.asList(
new Foo(1, "a"),
new Foo(2, "b"),
new Foo(3, "a"))
.stream()
.parallel()
.collect(HashMap::new,
(map, foo) -> {
map.computeIfAbsent(foo.getS(), s -> new ArrayList<>()).add(foo);
},
(left, right) -> {
for (HashMap.Entry<String, List<Foo>> e : right.entrySet()) {
left.merge(
e.getKey(),
e.getValue(),
(l1, l2) -> {
l1.addAll(l2);
return l1;
});
}
});
System.out.println(result); // {a=[1, 3], b=[2]}
Örnek - LinkedHashMapŞöyle yaparız. Burada Array içindeki string'lerin unique olduğu varsayılıyor.
List<String> myList = Arrays.asList("a", "bb", "ccc");
// or since java 9 List.of("a", "bb", "ccc");
LinkedHashMap<String, Integer> mapInOrder = myList
.stream()
.collect(
LinkedHashMap::new, // Supplier
(map, item) -> map.put(item, item.length()), // Accumulator
Map::putAll); // Combiner
System.out.println(mapInOrder); // {a=1, bb=2, ccc=3}
Örnek - LinkedHashSet
Şöyle yaparız
LinkedHashSet<Student> studentsLinkedHashSet = students().collect(
LinkedHashSet::new,
LinkedHashSet::add,
LinkedHashSet::addAll
);
Şöyle bir sınıfımız olsun.
// Averager.java from the official Java tutorial
public class Averager
{
private int total = 0;
private int count = 0;
public void addcount(int i) { total += i; count++;} //accumulator
public void combine(Averager other) { //combiner
total += other.total;
count += other.count;
}
}
Kendi metodlarımızı çağırmak istersek şöyle yaparız. Bir Averager nesnesi yaratılır. Her eleman için addCount metodu çağrılır. addAccount bir accumulator metodudur. Stream elemanını bir result container nesnesine ekler. combine bir combiner metodudur. İki tane result container nesnesini birleştirir.List<Integer> list = new LinkedList<Integer>();
...
Averager averageCollect = list.stream()
.collect(Averager::new, Averager::addcount, Averager::combine);
Eğer lambda kullanmak istersek şöyle yaparız.Averager averageCollect = list.stream()
.collect(Averager::new, (a,b) -> a.addcount(b), (a,b) -> a.combine(b));
Hiç yorum yok:
Yorum Gönder