Создать нулевое значение общего подкласса Number

Как я могу создать нуль произвольного числового типа?

Вот пример игрушки: функция, которая преобразует нулевое число в ноль.

static <T extends Number> T zeroIfNull(T value) {
    return value == null ? 0 : value;
}

Это не компилируется, потому что буквальный ноль имеет тип int, и мне нужно его преобразовать, чтобы набрать T.

Можно ли вообще это сделать?

Ответ 1

Zero даже не упоминается в классе Number. Если вы должны это сделать, и я предлагаю избегать null s, возможно:

public static <T> T coalesce(T a, T b) {
    return a==null ? b : a;
}

Вы также можете создать общий интерфейс для обработки чисел с функциями, которые имеют смысл для вашего кода:

interface NumberOps<T extends Number> {
    T zeroIfNull(T value);
}

Ответ 2

Можно ли вообще это сделать?
На самом деле, нет. С одной стороны, когда значение равно null, как метод узнает, какая реализация числа вернется?

Ответ 3

попробуйте:

   return value == null ? (T)Integer.valueOf(0) : value;

Ответ 4

Это старый вопрос, но после некоторого времени с этим вопросом я придумал решение, которое может представлять интерес для других:

@SuppressWarnings("unchecked")
public static <T extends Number> T getZero() {
    return (T)((Integer)0);
}

Это отлично работает, если речь идет об арифметических операциях, вы можете преобразовать экземпляр Number к известному типу, например:

double getSquareRoot(T x) {
    return Math.sqrt(x.doubleValue());
}

В таких ситуациях не имеет значения тип переменной, если это экземпляр Number, всегда можно получить двойной.

Ответ 5

Этот метод требует класса типов, поэтому вам нужен либо экземпляр объекта T для его получения, либо класс типов напрямую.

T castedValue = NumberCast.cast((Class<T>)someTObject.getClass(), 0d);

public class NumberCast
{
    public static <T extends Number> T cast(Class<T> typeClass, double value)
    {
        if (typeClass == Double.class)
            return typeClass.cast(value);
        else if (typeClass == Float.class)
            return typeClass.cast((float)value);
        else if (typeClass == Integer.class)
            return typeClass.cast((int)Math.round(value));
        else if (typeClass == Short.class)
            return typeClass.cast((short)Math.round(value));
        else if (typeClass == Long.class)
            return typeClass.cast(Math.round(value));

        return null;
    }
}

Ответ 6

Не то, что изящно, но я думаю в большинстве подобных случаев, что мы можем сделать:

static <T extends Number> T zeroIfNull(T value, Class<T> clazz) {...}

и при использовании:

BigDecimal v = zeroIfNull(orignalVal, BigDecimal.class);

Ответ 7

Вы можете использовать перегрузку метода для достижения этой цели:

public static Double getValue(Double value) {
  return value != null ? value : 0;
}

public static Long getValue(Long value) {
  return value != null ? value : 0;
}

public static Integer getValue(Integer value) {
  return value != null ? value : 0;
}

Ответ 8

import java . math . * ;

class Numbers
{
    public static < T extends Number > T zeroIfNull ( T number , Class<T> clazz ) throws IllegalArgumentException
    {
    if ( clazz == Integer . class )
        {
        return zeroIfNull ( number , clazz , 0 ) ;
        }
    else if ( clazz == Double . class )
        {
        return zeroIfNull ( number , clazz , 0 ) ;
        }
    else if ( clazz == BigInteger . class )
        {
        return zeroIfNull ( number , clazz , BigInteger . ZERO ) ;
        }
    // add a whole bunch more if statements
    throw new IllegalArgumentException ( "Unexpected Number Class " + clazz . getName ( ) + " with possibly undefined zero value." ) ;
    }

    private static < T extends Number > T zeroIfNull ( T number , Class<T> clazz , Object zero )
    {
    if ( number == null )
        {
        return ( clazz . cast ( zero ) ) ;
        }
    else
        {
        return ( number ) ;
        }
    }
}

Ответ 9

Ниже приводится улучшение моего первого ответа.

import java . math . * ;
import java . util . * ;

class Numbers
{
    private static final Map<Class<? extends Number>,Object> zeroes = new HashMap<Class<? extends Number>,Object> ( ) ;

    static
    {
         zeroes . put ( Integer . class , new Integer ( 0 ) ) ;
         zeroes . put ( Double . class , new Double ( 0.0 ) ) ;
         zeroes . put ( BigInteger . class , BigInteger . ZERO ) ;
         // fill it up with all supported classes
    }

    public static < T extends Number > T zeroIfNull ( T number , Class<T> clazz ) throws IllegalArgumentException
    {
    if ( number == null ) // return zero (if we know what zero is)
        {
        if ( zeroes . containsKey ( clazz ) )
            {
            return ( clazz . cast ( zeroes . get ( clazz ) ) ) ;
            }
        throw new IllegalArgumentException ( "Unexpected Number Class " + clazz . getName ( ) + " with undefined zero value." ) ;
        }
    return number ;
    }
}