Создать нулевое значение общего подкласса 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 ;
}
}