[英]Getting a ClassCastException when using a custom Collector with java 8 streams
I have a custom Collector
of the sort 我有一个自定义的
Collector
public class ClusteringCollector extends java.util.stream.Collector<MyModel, Map<String, ClusterModel>, SortedSet<Map.Entry<Integer, ClusterModel>>> {
@Override
public Supplier<Map<String, MyOtherModel>> supplier() {
return HashMap::new;
}
@Override
public BiConsumer<Map<String, ClusterModel>, MyModel> accumulator() {
return (l, r) -> {
String mapKey = r.getURI();
if(l.containsKey(mapKey)) {
l.get(mapKey).addCluster(r.getCluster());
} else {
l.put(mapKey, r.getCluster());
}
}
}
@Override
public BinaryOperator<Map<String, ClusterModel>> combiner() {
return (left, right) -> {
for(Map.Entry<String, ClusterModel> e : right.entrySet()) {
e.getValue().setClusterCount(1);
if(left.containsKey(e.getKey())) {
left.get(e.getKey()).merge(e.getValue());
} else {
left.put(e.getKey(), e.getValue());
}
}
return left;
};
}
@Override
public Function<Map<String, ClusterModel>, SortedSet<Map.Entry<Integer, ClusterModel>>> finisher() {
return (accumulated) -> {
SortedSet<Map.Entry<Integer, ClusterModel>> finished = new TreeSet<>((mine, theirs) -> {
Double t1 = mine.getValue().getClusterCount() * mine.getValue().getClusterWeight();
Double t2 = theirs.getValue().getClusterCount() * theirs.getValue().getClusterWeight();
return t2.compareTo(t1);
});
Map<Integer, ClusterModel> tempMap = new LinkedHashMap<>();
for(Map.Entry<String, ClusterModel> e : accumulated.entrySet()) {
if(tempMap.containsKey(e.getValue().hashCode())) {
tempMap.get(e.getValue().hashCode()).merge(e.getValue());
} else {
tempMap.put(e.getValue().hashCode(), e.getValue());
}
}
finished.addAll(tempMap.entrySet());
return finished;
};
}
@Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH);
}
}
I use the collector in the following way 我通过以下方式使用收集器
try (Stream<MyModel> resultStream = generateDataStream()) {
SortedSet<Map.Entry<Integer, ClusterModel>> clusters = resultStream.collect(new ClusteringCollector()); // This line throws a ClassCastException
}
The problem though is that I keep getting a ClassCastException
when I try to run the collect
method above. 问题是,当我尝试运行上面的
collect
方法时,我一直收到ClassCastException
。 Here is the stacktrace 这是堆栈跟踪
java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.SortedSet
com.mycomp.abc.core.services.DefaultClusteringServiceImpl.findClusters(DefaultClusteringServiceImpl.java:78)
com.mycomp.abc.core.webservices.ClusteringWebService.getClustersFromQuery(ClusteringWebService.java:67)
com.mycomp.abc.core.webservices.ClusteringWebService$Proxy$_$$_WeldClientProxy.getClustersFromQuery(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137)
org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296)
org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250)
org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237)
org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
org.jboss.resteasy.core.SynchronousDispatcher.invokePropagateNotFound(SynchronousDispatcher.java:217)
org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:224)
org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:62)
Can someone tell me why this is happening? 有人可以告诉我为什么会这样吗? I am not getting any compilation errors though and the
finisher
transforms the Map
into a SortedSet
correctly. 我没有收到任何编译错误,并且
finisher
将Map
正确转换为SortedSet
。
There are several errors in the posted code which suggest that this is not the actual code, however, the main problem is recognizable. 发布的代码中存在多个错误,表明这不是实际的代码,但是主要问题是可以识别的。 You specified the
IDENTITY_FINISH
characteristic, despite you have a complex conversion in the finisher. 尽管在装订器中进行了复杂的转换,但您仍指定了
IDENTITY_FINISH
特性。
The IDENTITY_FINISH
characteristic implies that the finisher was just like Function.identity()
, but at runtime, the Stream implementation can't check whether the generic signatures are compatible with that declaration. IDENTITY_FINISH
特性暗示整理器就像Function.identity()
,但是在运行时,Stream实现无法检查泛型签名是否与该声明兼容。 When it uses this characteristic to decide to skip the finisher, it will just return the container object, which is a HashMap
in your case, which, of course, is not assignable to SortedSet
. 当它使用此特性决定跳过装订器时,它将仅返回容器对象,在您的情况下是
HashMap
,当然,该对象不能分配给SortedSet
。
In the end, that's the better outcome of this mistake. 最后,这是此错误的更好结果。 The worse would be if the container and result type are compatible and the skipping of a nontrivial finisher stays unnoticed at first.
更糟糕的是,如果容器和结果类型兼容,并且起初没有忽略不重要的修整器的跳过。 So be careful about specifying the
IDENTITY_FINISH
characteristic. 因此,在指定
IDENTITY_FINISH
特征时要小心。
Note that when you don't implement Collector
, but rather construct one by passing the functions to Collector.of(…)
, you never need to specify that characteristic, as it will be injected based on whether you specified a finisher function or not. 请注意,当您不实现
Collector
,而是通过将函数传递给Collector.of(…)
来构造一个,则无需指定该特征,因为将根据您是否指定了finisher函数来注入该特征。 For the overloaded method without a finisher, the generic signature will even ensure that the container type matches the result type. 对于没有整理程序的重载方法,泛型签名甚至可以确保容器类型与结果类型匹配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.