PeM*_*eMa 8 java java-8 java-stream collectors
标准收集器在summingInt内部创建一个长度为1的数组:
public static <T> Collector<T, ?, Integer>
summingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new int[1],
(a, t) -> { a[0] += mapper.applyAsInt(t); },
(a, b) -> { a[0] += b[0]; return a; },
a -> a[0], CH_NOID);
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否不可能仅定义:
private <T> Collector<T, Integer, Integer> summingInt(ToIntFunction<? super T> mapper) {
return Collector.of(
() -> 0,
(a, t) -> a += mapper.applyAsInt(t),
(a, b) -> a += b,
a -> a
);
}
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用,因为似乎只是忽略了累加器。谁能解释这种行为?
And*_*lko 10
an Integer是不可变的,而Integer[]数组是可变的。一个累加器应该是有状态的。
想象一下,您有2个对2个Integer对象的引用。
Integer a = 1;
Integer b = 2;
Run Code Online (Sandbox Code Playgroud)
从本质上讲,您引用的实例是不可变的:创建实例后就无法对其进行修改。
Integer a = 1; // {Integer@479}
Integer b = 2; // {Integer@480}
Run Code Online (Sandbox Code Playgroud)
您已决定a用作累加器。
a += b;
Run Code Online (Sandbox Code Playgroud)
该值a当前保持令人满意。是3。但是,a不再指的是{Integer@479}您一开始就曾经拥有的。
我向您添加了调试语句Collector,并使事情变得清晰。
public static <T> Collector<T, Integer, Integer> summingInt(ToIntFunction<? super T> mapper) {
return Collector.of(
() -> {
Integer zero = 0;
System.out.printf("init [%d (%d)]\n", zero, System.identityHashCode(zero));
return zero;
},
(a, t) -> {
System.out.printf("-> accumulate [%d (%d)]\n", a, System.identityHashCode(a));
a += mapper.applyAsInt(t);
System.out.printf("<- accumulate [%d (%d)]\n", a, System.identityHashCode(a));
},
(a, b) -> a += b,
a -> a
);
}
Run Code Online (Sandbox Code Playgroud)
如果使用它,您会注意到类似
init [0 (6566818)]
-> accumulate [0 (6566818)]
<- accumulate [1 (1029991479)]
-> accumulate [0 (6566818)]
<- accumulate [2 (1104106489)]
-> accumulate [0 (6566818)]
<- accumulate [3 (94438417)]
Run Code Online (Sandbox Code Playgroud)
0 (6566818)尽管使用进行了所有失败的尝试,但哪里都没有更改+=。
如果改写为使用 AtomicInteger
public static <T> Collector<T, AtomicInteger, AtomicInteger> summingInt(ToIntFunction<? super T> mapper) {
return Collector.of(
() -> {
AtomicInteger zero = new AtomicInteger();
System.out.printf("init [%d (%d)]\n", zero.get(), System.identityHashCode(zero));
return zero;
},
(a, t) -> {
System.out.printf("-> accumulate [%d (%d)]\n", a.get(), System.identityHashCode(a));
a.addAndGet(mapper.applyAsInt(t));
System.out.printf("<- accumulate [%d (%d)]\n", a.get(), System.identityHashCode(a));
},
(a, b) -> { a.addAndGet(b.get()); return a;}
);
}
Run Code Online (Sandbox Code Playgroud)
您会看到一个真正的累加器(作为可变减少的一部分)在起作用
init [0 (1494279232)]
-> accumulate [0 (1494279232)]
<- accumulate [1 (1494279232)]
-> accumulate [1 (1494279232)]
<- accumulate [3 (1494279232)]
-> accumulate [3 (1494279232)]
<- accumulate [6 (1494279232)]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
114 次 |
| 最近记录: |