Wie bekannt, gibt "reduce" bei der Akkumulation immer ein neues unveränderliches Objekt zurück, während "collect" Änderungen an einem veränderlichen Objekt vornimmt.Java 8 collect vs. reduce
Wenn ich jedoch versehentlich eine Methodenreferenz sowohl für die Methode "Reduzieren" als auch für die Methode "Sammeln" zuweist, wird sie ohne Fehler kompiliert. Warum?
Werfen Sie einen Blick auf den folgenden Code:
public class Test {
@Test
public void testReduce() {
BiFunction<MutableContainer,Long,MutableContainer> func =
MutableContainer::reduce;
// Why this can compile?
BiConsumer<MutableContainer,Long> consume =
MutableContainer::reduce;
// correct way:
//BiConsumer<MutableContainer,Long> consume =
// MutableContainer::collect;
long param=10;
MutableContainer container = new MutableContainer(0);
consume.accept(container, param);
// here prints "0",incorrect result,
// because here we expect a mutable change instead of returning a immutable value
System.out.println(container.getSum());
MutableContainer newContainer = func.apply(container, param);
System.out.println(newContainer.getSum());
}
}
class MutableContainer {
public MutableContainer(long sum) {
this.sum = sum;
}
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
private long sum;
public MutableContainer reduce(long param) {
return new MutableContainer(param);
}
public void collect(long param){
this.setSum(param);
}
}
Ich denke, [15.13.2] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13.2) ist in diesem Fall relevanter - - "Ein Methodenreferenzausdruck ist in einem Zuordnungskontext [...] mit einem Zieltyp T [...] kompatibel, wenn [...]] Das Ergebnis des Funktionstyps [von T] ist ungültig " –
ok, ich denke, die Erklärung ist ziemlich klar. Nicht sicher, warum dies akzeptiert wird, da es in den meisten Fällen einen Fehler verursachen wird. Starke Typprüfung sollte diese Art von Fehler verhindern – ning
Sie haben Recht auf die Motivation.Wie Sie eine Methode aufrufen und den Rückgabetyp verwerfen können, können Sie eine result-pairing-Methode in eine void-zurückkehrende funktionale Schnittstelle konvertieren.Der vorherige Kommentator befürchtet, dass diese Flexibilität zu Fehlern führt, aber die Alternative war schlimmer - man konnte "aList :: add" nicht einmal zu einem "Consumer" konvertieren, da 'add' etwas zurückgibt - und das wäre wirklich ärgerlich, wenn man nicht' x.forEach sagen könnte (liste: : add) '! Entweder Lösung würde jemanden ärgern. Dieser Weg wurde als das kleinere Übel angesehen. Und wirklich, es war nicht einmal ein knapper Ruf. –