Map: method definition for Integer and Double, but not strings

I am trying to define a method putIfGreaterThan()for my new class Map(taking into account the key, it replaces the old value with the new value only if the new value is greater than the old value).

I understand that I could accomplish this either through composition (having private final Map<String, Double> map;in a new class and then passing the constructor Mapto the constructor) or implementing the interface Mapin my new class and passing to the Mapconstructor (although I'm not sure which approach is superior).

My main problem is that I need to be able to call the method putIfGreaterThan()on <String, Double>and <String, Integer>, but not on <String, String>(because it makes no sense to call it <String, String>), If I use generics ( <K, V>), the client can pass <String, String>, which is not allowed. On the other hand, if I allow Double, I will not be able to transmit Integeror vice versa. How can I define a method that allows either Integer or Double, but not String?

Note. I cannot define two constructors (one for Double and one for Integer) because I get an error: Erasure of method XX is the same as another method in type XX.

+4
source share
3 answers

Number, , , 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, .. , .

+2

, . - :

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);
        }
    }

}
0

, , extends V & Comparable<? super V>, Java.

However, you can define a static method without using &.

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);
}

If you are on the path of a different design, then the type should be different for the case when V- Comparable<? super V>. If two constructors have the same erase, it is probably time to use static creation methods.

0
source

Source: https://habr.com/ru/post/1672277/


All Articles