セコ:
単純なクラスを考えてみましょうFoo
:
public class Foo {
public Float v1;
public Float v2;
public String name;
public Foo(String name, Float v1, Float v2) {
this.name = name;
this.v1 = v1;
this.v2 = v2;
}
public String getName() {
return name;
}
}
今、私が持っているのコレクションFoo
のを、私はでグループ化したいと思いますFoo::getName
。私はそれを行うにはコレクターのカスタムを書きましたが、期待どおりに動作するようには思えません。より正確には、combiner()
呼ばれることは決してありません。どうして?
public class Main {
public static void main(String[] args) {
List<Foo> foos = new ArrayList<>();
foos.add(new Foo("blue", 2f, 2f));
foos.add(new Foo("blue", 2f, 3f));
foos.add(new Foo("green", 3f, 4f));
Map<String, Float> fooGroups = foos.stream().collect(Collectors.groupingBy(Foo::getName, new FooCollector()));
System.out.println(fooGroups);
}
private static class FooCollector implements Collector<Foo, Float, Float> {
@Override
public Supplier<Float> supplier() {
return () -> new Float(0);
}
@Override
public BiConsumer<Float, Foo> accumulator() {
return (v, foo) -> v += foo.v1 * foo.v2;
}
@Override
public BinaryOperator<Float> combiner() {
return (v1, v2) -> v1 + v2;
}
@Override
public Function<Float, Float> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
Set<Characteristics> characteristics = new TreeSet<>();
return characteristics;
}
}
}
rgettman:
まず、コンバイナ機能を使用すると、複数のスレッド(並列ストリーム)を使用していない場合に呼び出さ取得する必要はありません。コンバイナは、あなたのストリームのチャンクに操作の結果を結合するために呼び出されます。コンバイナを呼び出す必要はありませんので、何の並列処理は、ここではありません。
あなたはあなたのためにアキュムレータ関数のゼロ値を取得しています。表現
v += foo.v1 * foo.v2;
う代わる v
新しいとFloat
オブジェクト。オリジナルアキュムレータオブジェクトが変更されません。それはまだです0f
。また、Float
他の数値ラッパー型(等String
)不変であり、変更することはできません。
あなたは変更可能であるアキュムレータオブジェクトのいくつかの他の種類を必要とします。
class FloatAcc {
private Float total;
public FloatAcc(Float initial) {
total = initial;
}
public void accumulate(Float item) {
total += item;
}
public Float get() {
return total;
}
}
次に、あなたのカスタムを変更することができますCollector
使用しますFloatAcc
。新規供給FloatAcc
、通話accumulate
中accumulator
の機能を、など
class FooCollector implements Collector<Foo, FloatAcc, Float> {
@Override
public Supplier<FloatAcc> supplier() {
return () -> new FloatAcc(0f);
}
@Override
public BiConsumer<FloatAcc, Foo> accumulator() {
return (v, foo) -> v.accumulate(foo.v1 * foo.v2);
}
@Override
public BinaryOperator<FloatAcc> combiner() {
return (v1, v2) -> {
v1.accumulate(v2.get());
return v1;
};
}
@Override
public Function<FloatAcc, Float> finisher() {
return FloatAcc::get;
}
@Override
public Set<Characteristics> characteristics() {
Set<Characteristics> characteristics = new TreeSet<>();
return characteristics;
}
}
これらの変更により、私はあなたが期待しているものを手に入れます:
{green=12.0, blue=10.0}