我正在尝试为我的新putIfGreaterThan()
类定义一个方法Map
(给定一个键,只有当新值大于该值时,它才会将旧值替换为新值旧价值)。
我知道我可以通过合成(在新类中使用private final Map<String, Double> map;
然后将Map
传递给构造函数)或在新类中实现Map
接口来实现此目的并将Map
传递给构造函数(虽然我不确定哪种方法更优秀)。
我的主要问题是我需要能够在putIfGreaterThan()
和<String, Double>
上调用方法<String, Integer>
,而不能在<String, String>
上调用(因为它没有意义在<String, String>
上调用它。如果我使用泛型(<K, V>
),客户端可以传递<String, String>
,这是不允许的。另一方面,如果我允许Double
,我将无法通过Integer
,反之亦然。如何定义允许Integer或Double但不允许String的方法?
注意:我无法定义两个构造函数(一个用于Double,一个用于Integer)因为我得到错误:方法XX的擦除与XX类型中的另一个方法相同。
答案 0 :(得分:2)
您可以使用装饰器模式并将泛型限制为Number
的子类型,您可以通过this answer中的小技巧进行比较而不进行比较。它接受数字实例的字符串表示并创建BigDecimal
的实例 - 从而绕过任何类型的转换。
下面你会找到装饰器的相关实现细节,当然你需要覆盖Map
接口的其余方法。
public class GreaterThanDecorator<K, V extends Number> implements Map<K, V> {
private final Map<K, V> delegate;
public GreaterThanDecorator(Map<K, V> delegate) {
this.delegate = delegate;
}
public V putIfGreaterThan(K key, V value) {
V old = delegate.get(key);
if (old == null) {
delegate.put(key, value);
return null;
}
BigDecimal newValue = new BigDecimal(value.toString());
BigDecimal oldValue = new BigDecimal(old.toString());
if (newValue.compareTo(oldValue) >= 1)
old = delegate.put(key, value);
return old;
}
}
随意禁止Number
的其他子类型,即通过抛出异常,视情况而定。
答案 1 :(得分:0)
遗憾的是,泛型和数字并不能很好地结合在一起。但你可以这样做:
public class MyMap {
private final Map<String, Number> map = new HashMap<>();
public void putInt(String key, int value) {
map.put(key, value);
}
public void putDouble(String key, int value) {
map.put(key, value);
}
public void putIfGreaterThan(String key, Number value) {
if (value instanceof Double) {
double doubleValue = (Double) value;
map.compute(key, (k, v) -> {
if (!(v instanceof Double) || v.doubleValue() > doubleValue) {
return v;
} else {
return value
}
});
} else if (value instanceof Integer) {
int intValue = (Integer) value;
map.compute(key, (k, v) -> {
if (!(v instanceof Integer) || v.intValue() > intValue) {
return v;
} else {
return value
}
});
} else {
throw new IllegalArgumentException("Expected Double or Integer, but got " + value);
}
}
}
答案 2 :(得分:0)
理想情况下,您需要声明一个引入类型参数extends V & Comparable<? super V>
的方法,但该方法不是有效的Java。
但是,您可以在不使用&
的情况下定义静态方法。
public static <K, V extends Comparable<? super V>> void putIfGreater(
Map<K,V> map, K key, V value
) {
V old = map.get(key);
if (old != null && value.compareTo(old) > 0) {
map.put(key, value);
}
// Or:
//map.computeIfPresent(key, (k, old) -> value.compareTo(old) > 0 ? value : old);
}
如果您沿着不同构造的路线走下去,那么V
为Comparable<? super V>
的情况下类型需要不同。如果两个构造函数具有相同的擦除,那么可能是时候有意义地命名静态创建方法了。