I've got a little but annoying problem with use of Generics in a Function.
The Function has to convert into a Double
any value that could be BigDecimal
or BigInteger
. That's why I designed it with a <T>
type for incoming argument.
The problem is that when I'm using it, I have to cast the given argument with <T>
...
Here is the code of the Function:
private Function<T, Double> bigToDouble = value -> {
BigDecimal bigDec = null;
if (value instanceof BigInteger) {
BigInteger bigInt = (BigInteger) value;
bigDec = new BigDecimal(bigInt);
}
if (value instanceof BigDecimal) {
bigDec = (BigDecimal) value;
}
return NumberUtils.toDouble(bigDec, NumberUtils.DOUBLE_ZERO);
};
When I test it, I've got an error if I do not cast the given argument with <T>
:
BigDecimal bigDec = new BigDecimal("2.5");
BigInteger bigInt = new BigInteger("150000");
System.out.println("FUNCTION TEST = " + bigToDouble.apply((T) bigInt));
System.out.println("FUNCTION TEST = " + bigToDouble.apply((T) bigDec));
What I expect is to call it this way, simply:
bigToDouble.apply(bigInt)
How should I design it to avoid such behaviour?
Did you try using the parent class of BigInteger
and BigDecimal
, Number
?
Instead of using generics, try replacing T
with Number
, which accepts both BigInteger
and BigDecimal
. This would look like the following code:
private Function<Number, Double> bigToDouble = value -> {
BigDecimal bigDec = null;
if (value instanceof BigInteger) {
BigInteger bigInt = (BigInteger) value;
bigDec = new BigDecimal(bigInt);
}
if (value instanceof BigDecimal) {
bigDec = (BigDecimal) value;
}
return NumberUtils.toDouble(bigDec, NumberUtils.DOUBLE_ZERO);
};
public void test(){
BigDecimal bigDec = new BigDecimal("2.5");
BigInteger bigInt = new BigInteger("150000");
System.out.println("FUNCTION TEST = " + bigToDouble.apply(bigInt));
System.out.println("FUNCTION TEST = " + bigToDouble.apply(bigDec));
}
EDIT
In case you want to use your own <T>
type parameter, without having the limitations that you will have when using <T>
now, you should declare a generic method. (see: https://docs.oracle.com/javase/tutorial/java/generics/methods.html ). The code for that would look like the following then:
private <T extends Number> Function<T, Double> bigToDouble() {
return value -> {
BigDecimal bigDec = null;
if (value instanceof BigInteger) {
BigInteger bigInt = (BigInteger) value;
bigDec = new BigDecimal(bigInt);
}
if (value instanceof BigDecimal) {
bigDec = (BigDecimal) value;
}
return NumberUtils.toDouble(bigDec, NumberUtils.DOUBLE_ZERO);
};
}
public void test() {
BigDecimal bigDec = new BigDecimal("2.5");
BigInteger bigInt = new BigInteger("150000");
System.out.println("FUNCTION TEST = " + bigToDouble().apply(bigInt));
System.out.println("FUNCTION TEST = " + bigToDouble().apply(bigDec));
}
如果您明确声明了T的界限(如<T extends Number>
它会改变吗?
The reason that you need a cast from BigInteger
/ BigDecimal
to T
is that at compile time, the compiler doesn't know what exactly the type T
is, so the compiler is not sure if it can cast the BigInteger
/ BigDecimal
to the type T
. Thus, you need to do a force cast.
To solve this, one solution is to replace T
by the parent class of your parameters classes. Thus the compiler is sure that it can do a downcasting.
Otherwise, you have to tell the compiler explicitly that you know at runtime, when you declare the type T
, you are sure that BigInteger
or BigDecimal
can be cast to this type. Which means that you have to write a force cast every time you invoke the apply
method.
Below the code :
public static void main(String[] args) {
Function<Number, Double> bigToDouble = value -> {
BigDecimal bigDec = null;
if (value instanceof BigInteger) {
BigInteger bigInt = (BigInteger) value;
bigDec = new BigDecimal(bigInt);
}
if (value instanceof BigDecimal) {
bigDec = (BigDecimal) value;
}
return bigDec.doubleValue();
};
BigDecimal bigDec = new BigDecimal("2.5");
BigInteger bigInt = new BigInteger("150000");
System.out.println("FUNCTION TEST = " + bigToDouble.apply(bigInt));
System.out.println("FUNCTION TEST = " + bigToDouble.apply(bigDec));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.