How can I generically create a zero of an arbitrary numeric type?
Here's a toy example: a function that converts a null number into zero.
static <T extends Number> T zeroIfNull(T value) {
return value == null ? 0 : value;
}
This doesn't compile because the literal zero is of type int
, and I need to convert that to type T
.
Is it possible to do this at all?
Ноль даже не упоминается в классе 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);
}
Следующее - улучшение моего первого ответа.
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 ;
}
}
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 ) ;
}
}
}
Возможно ли это вообще сделать?
Не совсем. Во-первых, когда значение равно null, как метод узнает, какую реализацию Number возвращать?
попробуйте:
return value == null ? (T)Integer.valueOf(0) : value;
Не очень элегантно, но я думаю, что в большинстве подобных случаев мы можем сделать это:
static <T extends Number> T zeroIfNull(T value, Class<T> clazz) {...}
и при использовании:
BigDecimal v = zeroIfNull(orignalVal, BigDecimal.class);