将java泛型错误与映射和收集器混淆
不久前,我发现了以下有关使用Java 8初始化映射的更干净方法的信息: 使用这些指导原则,我在一个应用程序中实现了以下类:将java泛型错误与映射和收集器混淆,java,eclipse,generics,java-8,java-stream,Java,Eclipse,Generics,Java 8,Java Stream,不久前,我发现了以下有关使用Java 8初始化映射的更干净方法的信息: 使用这些指导原则,我在一个应用程序中实现了以下类: public class MapUtils { public static <K, V> Map.Entry<K, V> entry(K key, V value) { return new AbstractMap.SimpleEntry<>(key, value); } public stati
public class MapUtils {
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleEntry<>(key, value);
}
public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() {
return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue());
}
public static <K, U> Collector<Map.Entry<K, U>, ?, ConcurrentMap<K, U>> entriesToConcurrentMap() {
return Collectors.toConcurrentMap((e) -> e.getKey(), (e) -> e.getValue());
}
}
公共类MapUtils{
公共静态映射。条目(K键,V值){
返回新的AbstractMap.SimpleEntry(键,值);
}
公共静态收集器entriesToMap(){
返回Collectors.toMap((e)->e.getKey(),(e)->e.getValue());
}
公共静态收集器entriesToConcurrentMap(){
返回Collectors.toConcurrentMap((e)->e.getKey(),(e)->e.getValue());
}
}
在该应用程序中,我实现了如下代码:
public Map<String, ServiceConfig> serviceConfigs() {
return Collections.unmodifiableMap(Stream.of(
entry("ActivateSubscriber", new ServiceConfig().yellowThreshold(90).redThreshold(80)),
entry("AddAccount", new ServiceConfig().yellowThreshold(90).redThreshold(80).rank(3)),
...
).
collect(entriesToMap()));
}
公共地图服务配置(){
返回集合。不可修改映射(Stream.of(
条目(“ActivateSubscriber”,new ServiceConfig().yellowThreshold(90).redThreshold(80)),
条目(“AddAccount”,new ServiceConfig().yellowThreshold(90).redThreshold(80).rank(3)),
...
).
收集(entriesToMap());
}
这段代码运行得非常好
在另一个应用程序中,我将MapUtils类复制到一个包中,并以与在另一个应用程序中相同的方式在一个类中导入该类
我输入以下内容以引用此内容:
Map<String, USLJsonBase> serviceRefMap =
Collections.unmodifiableMap(Stream.of(
entry("CoreService", coreService),
entry("CreditCheckService", creditCheckService),
entry("PaymentService", paymentService),
entry("AccountService", accountService),
entry("OrdercreationService", orderCreationService),
entry("ProductAndOfferService", productAndOfferService),
entry("EquipmentService", equipmentService),
entry("EvergentService", evergentService),
entry("FraudCheckService", fraudCheckService)
).
collect(entriesToMap()));
Map服务refmap=
集合。不可修改的映射(Stream.of(
条目(“CoreService”,CoreService),
条目(“CreditCheckService”,CreditCheckService),
条目(“PaymentService”,PaymentService),
条目(“AccountService”,AccountService),
条目(“OrdercreationService”,OrdercreationService),
条目(“ProductAndOfferService”,ProductAndOfferService),
条目(“设备服务”,设备服务),
条目(“EvergentService”,EvergentService),
条目(“FraudCheckService”,FraudCheckService)
).
收集(entriesToMap());
在“对方付费”电话中,Eclipse告诉我以下内容:
The method collect(Collector<? super Map.Entry<String,? extends USLJsonBase>,A,R>) in the type Stream<Map.Entry<String,? extends USLJsonBase>> is not applicable for the arguments (Collector<Map.Entry<Object,Object>,capture#1-of ?,Map<Object,Object>>)
方法collect(Collector问题在于,Stream.of(…).collect(…)
是一个方法调用链,目标类型不会通过这样的链传播。因此,当您将结果分配给参数化的映射
时,收集
调用会考虑这些类型参数(和嵌套的entriesToMap()
调用),但不适用于(…)
调用的流
因此,为了推断通过(…)
的流创建的流的类型,只考虑参数的类型
Map<String,Integer> map = Stream.of(entry("foo", 42), entry("bar", 100))
.collect(entriesToMap());
Map<String,Number> map = Stream.of(entry("foo", 42L), entry("bar", 100))
.collect(entriesToMap());
不起作用,因为推断的流类型是流
,收集器不接受该类型来生成映射
这就引出了一个解决方案,可以放松收集器的通用签名
public static <K, U>
Collector<Map.Entry<? extends K, ? extends U>, ?, Map<K, U>> entriesToMap() {
return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue());
}
使用起来更简单:
Map<String,Integer> map1 = mapOf(entry("foo", 42), entry("bar", 100));
Map<String,Number> map2 = mapOf(entry("foo", 42), entry("bar", 100));
Map<String,Number> map3 = mapOf(entry("foo", 42L), entry("bar", 100));
Map map1=mapOf(条目(“foo”,42),条目(“bar”,100));
Map map2=mapOf(条目(“foo”,42),条目(“bar”,100));
Map map3=mapOf(条目(“foo”,42L),条目(“bar”,100));
请注意,由于此用法仅包含嵌套调用(无链),目标类型推断在整个表达式中都起作用,即在没有工厂方法的通用签名中的
?extends
的情况下也能起作用。但是为了最大的灵活性,仍然建议使用这些通配符。可以先将流分配给变量,或者添加类型提示。或者,在Java 9中,使用Map.of
。在dupe中检查我的答案(我不确定它是否是dupe;将从实际计算机重新打开)。那里有一个Javac标志,它将打开类型推断算法的扩展调试信息。这可能会给出区别的线索。你知道如何让Eclipse使用该标志吗?@DavidM.Karr。你可以设置的所有内容都在RunAs->Run Configuration中。关于你对工作类型的猜测失败的情况下,工作情况下所有的值都具有相同的类型,在失败的情况下,所有的值都是map-value类型的子类的实例。
public static <K, U>
Collector<Map.Entry<? extends K, ? extends U>, ?, Map<K, U>> entriesToMap() {
return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue());
}
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleImmutableEntry<>(key, value);
}
@SafeVarargs
public static <K, V> Map<K,V> mapOf(Map.Entry<? extends K, ? extends V>... entries) {
return Stream.of(entries)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
@SafeVarargs
public static <K, V> ConcurrentMap<K,V> concurrentMapOf(
Map.Entry<? extends K, ? extends V>... entries) {
return Stream.of(entries)
.collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
}
Map<String,Integer> map1 = mapOf(entry("foo", 42), entry("bar", 100));
Map<String,Number> map2 = mapOf(entry("foo", 42), entry("bar", 100));
Map<String,Number> map3 = mapOf(entry("foo", 42L), entry("bar", 100));