Frage Wie funktioniert der Combiner in der Stream.collect-Methode in Java 8?


Ich habe eine einfache Demo erstellt:

public static void main(String[] args) {
        List<String> list2 = Arrays.asList("adf", "bcd", "abc", "hgr", "jyt", "edr", "biu");

String collect = list2.stream().collect(String::new, (res, elem) -> {
              res=res.concat(" ").concat(elem);
//            System.out.printf("res=%s, elem=%s\n", res.isEmpty(), elem);

        }, (res1, res2) -> {
            System.out.printf("res1=%s, res2=%s\n", res1, res2);            
        });
        System.out.println("collect=" + collect);
}

Das Problem ist, dass BiConsumer combiner Teil von collect läuft überhaupt nicht.

Es läuft wenn ich es benutze parallelStream() aber zwei Argumente res1 und res2 sind gleich dem Lieferanten String::new.

Wie man ... macht combiner in ... Arbeiten collect Methode?


22
2018-04-30 05:38


Ursprung


Antworten:


Zunächst einmal muss der Kombinator nicht in einem nichtparallelen Strom ausgeführt werden, da nichts zu kombinieren ist.

Zweitens, Ihr Problem ergibt sich aus der Verwendung String::new und String.concat. Der Akkumulator soll das erste Argument modifizieren, indem er das zweite Argument damit kombiniert, aber da Strings in Java unveränderlich sind, wird Ihr Code nichts produzieren.

          res=res.concat(" ").concat(elem);

wird eine neue Zeichenfolge erstellen und dann wegwerfen. Sie möchten stattdessen einen StringBuilder verwenden, damit Sie die Zwischenergebnisse behalten können:

public static void main(String[] args) {
    List<String> list2 = Arrays.asList("adf", "bcd", "abc", "hgr", "jyt", "edr", "biu");

    String collect = list2.stream().collect(StringBuilder::new, (res, elem) -> {
        res.append(" ").append(elem);
    }, (res1, res2) -> {
        res1.append(res2.toString());
        System.out.printf("res1=%s, res2=%s\n", res1, res2);
    }).toString();
    System.out.println("collect=" + collect);
}

Dies funktioniert auch korrekt mit einem parallelen Stream

res1 = hgr jyt, res2 = jyt
  res1 = bcd abc, res2 = abc
  res1 = adf bcd abc, res2 = bcd abc
  res1 = edr biu, res2 = biu
  res1 = hgr jyt edr biu, res2 = edr biu
  res1 = adf bcd abc hgr jyt edr biu, res2 = hgr jyt edr biu
  sammeln = adf bcd abc hgr jyt edr biu


15
2018-04-30 06:18



ich glaube, dass der combiner wird nur in parallelen Streams verwendet (um die partiellen Ausgaben der parallelen Berechnungen zu kombinieren), also mach deinen Stream parallel.

String collect = list2.parallelStream().collect(...

8
2018-04-30 05:44



Es ist interessanteres Ergebnis mit und ohne Parallele für Raniz Probe:

    String collect = list2.stream().collect(StringBuilder::new,
            (res, elem) -> {
                System.out.printf("ACCUMULATE res=%s, elem=%s\n", res, elem);
                res.append(" ").append(elem);
        },
            (res1, res2) -> {
                System.out.printf("COMBINE res1=%s, res2=%s\n", res1, res2);
                res1.append(res2.toString());
            }).toString();

Ohne Parallele Kombination wurde nie genannt:

ACCUMULATE res=, elem=adf
ACCUMULATE res= adf, elem=bcd
ACCUMULATE res= adf bcd, elem=abc
ACCUMULATE res= adf bcd abc, elem=hgr
ACCUMULATE res= adf bcd abc hgr, elem=jyt
ACCUMULATE res= adf bcd abc hgr jyt, elem=edr
ACCUMULATE res= adf bcd abc hgr jyt edr, elem=biu
collect= adf bcd abc hgr jyt edr biu

Und mit parallel

ACCUMULATE res=, elem=jyt
ACCUMULATE res=, elem=hgr
COMBINE res1= hgr, res2= jyt
ACCUMULATE res=, elem=biu
ACCUMULATE res=, elem=edr
COMBINE res1= edr, res2= biu
ACCUMULATE res=, elem=bcd
COMBINE res1= hgr jyt, res2= edr biu
ACCUMULATE res=, elem=abc
ACCUMULATE res=, elem=adf
COMBINE res1= bcd, res2= abc
COMBINE res1= adf, res2= bcd abc
COMBINE res1= adf bcd abc, res2= hgr jyt edr biu
collect= adf bcd abc hgr jyt edr biu

2
2017-08-08 10:59