标签:
上一篇博文java8函数式编程--收集器collector:(http://my.oschina.net/joshuashaw/blog/487322)讲得比较随性,并没有把源码一句一句拿出来分析,后来发现groupingBy方法最后有一个if-else分支用来返回不同类型的collector,一个是不需要特定finisher的,另一个需要使用下游收集器的finisher,今天细看源码,发现了几句神奇的代码,拿出来讲一讲。
先贴源码:
public static >
Collector groupingBy(Function super T, ? extends K> classifier,
Supplier mapFactory,
Collector super T, A, D> downstream) {
Supplier downstreamSupplier = downstream.supplier();
BiConsumer downstreamAccumulator = downstream.accumulator();
BiConsumer, T> accumulator = (m, t) -> {
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
downstreamAccumulator.accept(container, t);
};
BinaryOperator> merger = Collectors.>mapMerger(downstream.combiner());
@SuppressWarnings("unchecked")
Supplier> mangledFactory = (Supplier>) mapFactory;
if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
}
else {
/*---------------------------
---- --神奇的代码-- ------
-----------------------------
@SuppressWarnings("unchecked")
Function downstreamFinisher = (Function) downstream.finisher();
Function, M> finisher = intermediate -> {
intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
@SuppressWarnings("unchecked")
M castResult = (M) intermediate;
return castResult;
};
-----------------------------
----- ---神奇的代码----- ----
--------------------------*/
return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
}
}
抽出来强调一下
@SuppressWarnings("unchecked")
Function downstreamFinisher = (Function) downstream.finisher();
Function, M> finisher = intermediate -> {
intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
@SuppressWarnings("unchecked")
M castResult = (M) intermediate;
return castResult;
};
这里我们看到,类型为
(Function) downstream.finisher()
被强制类型转换成
(Function) downstreamFinisher
然后是
Map intermediate
被强制类型转换成
Map intermediate
我想,这都行?于是我写了两条语句
Fuction f1 = Integer::parse;
Fuction f2 = (Fuction) f1;
编译器报错。
但是为什么groupingBy方法里面可以这样写?于是我按照groupingBy方法写了一个测试类,代码如下:
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class InterestingTest {
private Map Tmap = null;
private Map Vmap = null;
private Function Vf = null;
private Function Tf = null;
public InterestingTest(Map m,Function f){
Tmap = m;
Vf = f;
Tf = (Function) f;
Tmap.replaceAll((k,t)->Tf.apply(t));
Vmap = (Map) Tmap;
}
public Map getMap(){
return Vmap;
}
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("1", 1);
map.put("2", 2);
map.put("3", 3);
map.put("4", 4);
Map newMap =
new InterestingTest(map,Integer::toBinaryString)
.getMap();
newMap.entrySet().stream()
.forEach(e->{System.out.println(e.getKey()+" "+e.getValue());});
}
}
代码只是报警告,一运行下来一点问题都没有,完美得出结果。
几天前刷知乎看到java实现不了真正的泛型,现在算是明白了。
其实,对于java泛型的实现,只是编译器在编译阶段帮助你进行类型转型,像Map类型,实际是保存你的对象的地址,对于Map来说,他只是存了Integer的地址,将Integer视为终极父类Object的子类,当你调用get(key)的时候,最后返回Object类型给你之前帮你强制类型转换成了Integer,就像:
put(key,IntegerObject){
this.object = IntegerObject;
}
get(key){
return (Integer) findCorrentObject;
}
所以从泛型的角度看,代码没有错误,但是会警告你这代码可能导致类型转换而出现的错误,于是我们可以看到
@SuppressWarnings("unchecked")
来去除警告。
但是,当你使用的是具体的类型时,编译器有职责给你报错,他认为你写的这行代码很有可能发生错误。
总结:都是兼容和初始开发人员省事而留下的问题啊。
标签: