我的方法应该只接受Map
,其键的类型为String
,值为Integer
或 String
,但不,比如,Boolean
。
例如,
map.put("prop1", 1); // allowed
map.put("prop2", "value"); // allowed
map.put("prop3", true); // compile time error
无法按以下方式声明Map(以强制执行编译时检查)。
void setProperties(Map<String, ? extends Integer || String> properties)
除了将值类型声明为unbounded wildcard
并在运行时验证Integer
或String
之外,最佳选择是什么?
void setProperties(Map<String, ?> properties)
此方法接受一组属性以配置基础服务实体。该实体仅支持String
和Integer
类型的属性值。例如,属性maxLength=2
有效,defaultTimezone=UTC
也有效,但allowDuplicate=false
无效。
答案 0 :(得分:5)
另一种解决方案是自定义Map
实施,并覆盖put
和putAll
方法来验证数据:
public class ValidatedMap extends HashMap<String, Object> {
@Override
public Object put(final String key, final Object value) {
validate(value);
return super.put(key, value);
}
@Override
public void putAll(final Map<? extends String, ?> m) {
m.values().forEach(v -> validate(v));
super.putAll(m);
}
private void validate(final Object value) {
if (value instanceof String || value instanceof Integer) {
// OK
} else {
// TODO: use some custom exception
throw new RuntimeException("Illegal value type");
}
}
}
注意:使用符合您需求的Map
实现作为基类
答案 1 :(得分:3)
由于类层次结构中Integer
和String
最接近的共同祖先是Object
,你无法实现你想要做的事情 - 你可以帮助编译器将类型缩小到{{1只有。
你可以
Object
或Integer
,或延长{@ 1}},如@ RC的答案,或
在课程中包装2 String
答案 2 :(得分:2)
定义两个重载:
void setIntegerProperties(Map<String, Integer> properties)
void setStringProperties(Map<String, String> properties)
它们必须被称为不同的东西,因为你不能有两种方法具有相同的擦除。
答案 3 :(得分:1)
我相当肯定,如果任何语言不允许多个接受类型的值,它将是Java。如果你真的需要这种能力,我建议你研究其他语言。 Python绝对可以做到。
将整数和字符串作为地图值的用例是什么?如果我们真的只处理整数和字符串,那么您将不得不:
Map<String, String> map;
Integer myValue = 5;
if (myValue instanceof Integer) {
String temp = myValue.toString();
map.put(key, temp);
}
// taking things out of the map requires more delicate care.
try { // parseInt() can throw a NumberFormatException
Integer result = Integer.parseInt(map.get(key));
}
catch (NumberFormatException e) {} // do something here
这是一个非常难看的解决方案,但它可能是使用Java提供的唯一合理解决方案之一,以保持对您的值的强烈打字感。
答案 4 :(得分:1)
您不能将类型变量声明为两种类型之一。但是您可以创建一个帮助程序类来封装没有公共构造函数的值,而不是专用类型的工厂方法:
public static final class Value {
private final Object value;
private Value(Object o) { value=o; }
}
public static Value value(int i) {
// you could verify the range here
return new Value(i);
}
public static Value value(String s) {
// could reject null or invalid string contents here
return new Value(s);
}
// these helper methods may be superseded by Java 9’s Map.of(...) methods
public static <K,V> Map<K,V> map(K k, V v) { return Collections.singletonMap(k, v); }
public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2) {
final HashMap<K, V> m = new HashMap<>();
m.put(k1, v1);
m.put(k2, v2);
return m;
}
public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3) {
final Map<K, V> m = map(k1, v1, k2, v2);
m.put(k3, v3);
return m;
}
public void setProperties(Map<String, Value> properties) {
Map<String,Object> actual;
if(properties.isEmpty()) actual = Collections.emptyMap();
else {
actual = new HashMap<>(properties.size());
for(Map.Entry<String, Value> e: properties.entrySet())
actual.put(e.getKey(), e.getValue().value);
}
// proceed with actual map
}
如果您使用带有地图构建器的第三方库,则不需要map
方法,它们仅适用于短地图。使用此模式,您可以调用类似
setProperties(map("mapLength", value(2), "timezone", value("UTC")));
由于Value
和int
只有两个String
工厂方法,因此不能将其他类型传递给地图。请注意,这也允许使用int
作为参数类型,因此可以将byte
,short
等扩展为int
。