Why can't I calculate with Number interface? - java

I wanted to make such class for calculating average value:
public static class AverageValue<T extends Number> {
T data = 0; //ERROR: incompatible types: int cannot be converted to T
int count = 0;
public AverageValue() {}
public AverageValue(T data) {
this.data = data;
count = 1;
}
public void add(T num) {
data+=num; //ERROR: bad operand types for binary operator '+'
count++;
}
public T average() {
return data/(T)count; //ERROR: incompatible types: int cannot be converted to T
}
}
I am not really getting why do we have interface Number if it doesn't abstract number. Because that's what interfaces do - abstract operations with data without holding the data themselves.
The above also makes it clear that you'll probably not be ever able to make your own number implementation (eg. number with unlimited size and precision for some really freaky experimental math programs).
I tried the same with Number instead of generic T with the very same results. Only difference is that Number x = 0 is actually valid.
Is there a way to trick java to compile this or do I have to be a "professional" java programmer and use doubles to calculate averages on byte arrays?

I am not really getting why do we have interface Number if it doesn't abstract number
interface Number does abstract the number for the purposes of storing and converting representations. It does not abstract the number for the purposes of making calculations, because the type of the result representation is not well defined.
The above also makes it clear that you'll probably not be ever able to make your own number implementation (eg. number with unlimited size and precision for some really freaky experimental math programs).
BigDecimal does it without any problem.
Number x = 0 is actually valid.
assigning Integer to Number is OK. Assigning Integer to something that extends Number (say, Double) is not OK. That's why there is a difference.
Is there a way to trick java to compile this or do I have to go full retard professional Java programmer and use doubles to calculate averages on byte arrays?
You need to specify the desired representation of the result when you compute the average. You could abstract it out yourself and supply the "averager" ingerface, but the information about the desired representation needs to get into the method in one way or the other:
interface AverageMaker<T extends Number> {
T initialResult();
T add(T a, Number b);
T divideByCount(T a, int b);
}
public static <T extends Number, R extends Number> R averageValue(Iterable<T> items, AverageMaker<R> maker) {
R res = maker.initialResult();
int count = 0;
for (T val : items) {
res = maker.add(res, val);
count++;
}
return maker.divideByCount(res, count);
}
Define several average makers, like this:
static final AverageMaker<Double> doubleAvg = new AverageMaker<Double>() {
public Double initialResult() { return 0.0; }
public Double add(Double a, Number b) { return a + b.doubleValue(); }
public Double divideByCount(Double a, int b) { return a/b; }
};
static final AverageMaker<Integer> intAvg = new AverageMaker<Integer>() {
public Integer initialResult() { return 0; }
public Integer add(Integer a, Number b) { return a + b.intValue(); }
public Integer divideByCount(Integer a, int b) { return a/b; }
};
Now you can use them in your code together with the averageValue method:
List<Integer> a = new ArrayList<Integer>();
a.add(4);
a.add(8);
a.add(91);
a.add(18);
double avgDouble = averageValue(a, doubleAvg);
int avgInt = averageValue(a, intAvg);
System.out.println(avgDouble); // Prints 30.25
System.out.println(avgInt); // Prints 30
Demo.

You could work with doubles in the class. Since the average of Integers is a Double, this should be correct.
public class AverageValue<T extends Number> {
double data = 0;
int count = 0;
public AverageValue() {
}
public AverageValue(T data) {
this.data = data.doubleValue();
count = 1;
}
public void add(T num) {
data += num.doubleValue();
count++;
}
public double average() {
return data / count;
}
}
This compiles. Usage:
AverageValue<Integer> avgInt = new AverageValue<>();
avgInt.add(1);
avgInt.add(2);
avgInt.add(3);
avgInt.add(4);
System.out.println(avgInt.average());
AverageValue<Double> avgDouble = new AverageValue<>();
avgDouble.add(1.1);
avgDouble.add(1.2);
avgDouble.add(1.3);
avgDouble.add(1.4);
System.out.println(avgDouble.average());
Output:
2.5
1.25

You are mixing up classes (Number) and primitive types (int). Operators like + or \ are not supported for numeric classes (+ is supported for strings, but that's a special case; and unlike e.g. C#, Java does not support custom operator overloading).
A "number with unlimited size and precision for some really freaky experimental math programs" is actually supported with the BigDecimal class, which shows that (and how) you can indeed have your own Number implementation.

ERROR: incompatible types: int cannot be converted to T
T data = (T)(Integer)0;
ERROR: bad operand types for binary operator '+'
ERROR: incompatible types: int cannot be converted to T
in java doesn't exist operator overload Why doesn't Java need Operator Overloading?

Related

Java Generic Methods Motivation [duplicate]

I am trying to understand bounded types and not quite grasping the point of them.
There is an example of bounded generics on which provides this use case:
public class NaturalNumber<T extends Integer> {
private T n;
public NaturalNumber(T n) { this.n = n; }
public boolean isEven() {
return n.intValue() % 2 == 0;
}
// ...
}
If you are going to restrict the classes that can be the parameterized type, why not just forget the parameterization all together and have:
public class NaturalNumber {
private Integer n;
public NaturalNumber(Integer n) { this.n = n; }
public boolean isEven() {
return n.intValue() % 2 == 0;
}
// ...
}
Then any class that extends/implements Integer can be used with this class.
Also, a side question: How is T extending Integer in the first example when the Java Integer class is final?
How is T extending Integer in the first example when the Java Integer class is final?
T can only be Integer, so the "extends" here is purely symbolic. (I'm starting with the side-note because, indeed, it's an example where generics are useless. I truly have no idea why the tutorial thinks this is an informative demonstration. It's not.)
Suppose instead that T extends Number:
class Example<T extends Number> {
private T num;
void setNum(T num) { this.num = num; }
T getNum() { return num; }
}
So the point of generics in general, is that you can do this:
Example<Integer> e = new Example<>();
e.setNum( Integer.valueOf(10) );
// returning num as Integer
Integer i = e.getNum();
// and this won't compile
e.setNum( Double.valueOf(10.0) );
Generics are a form of parametric polymorphism, essentially it lets us reuse code with a generality regarding the types involved.
So what's the point of a bound?
A bound here means that T must be Number or a subclass of Number, so we can call the methods of Number on an instance of T. Number is unfortunately a generally useless base class on its own (because of precision concerns), but it might let us do something interesting like:
class Example<T extends Number> extends Number {
// ^^^^^^^^^^^^^^
...
#Override
public int intValue() {
return num.intValue();
}
// and so on
}
It's more common, for example, to find T extends Comparable<T> which lets us do something more meaningful with T. We might have something like:
// T must be a subclass of Number
// AND implement Comparable
Example<T extends Number & Comparable<T>>
implements Comparable<Example<T>> {
...
#Override
public int compareTo(Example<T> that) {
return this.num.compareTo(that.num);
}
}
And now our Example class has a natural ordering. We can sort it, even though we have no idea what T actually is inside the class body.
If we combine these concepts, that:
generics allow the "outside world" to specify an actual type and
bounds allow the "inside world" to use a commonality,
we could build constructs such as:
static <T extends Comparable<T>> T min(T a, T b) {
return (a.compareTo(b) < 0) ? a : b;
}
{
// returns "x"
String s = min("x", "z");
// returns -1
Integer i = min(1, -1);
}

Binary Calculations on a Bounded Generic Type

I want to create a function to calculate the power of a number of the type Number (the class) via recursion. There is an issue in the following line:
return base * NumberOpp.power(base, pow - 1);
It doesn't know how to perform the '*' operation. I am guessing this is because of the generic type. It is bounded which I think would fix the problem. I tried casting (it's a little ugly.) It didn't seem to work either.
return (T) (Number.doubleValue(base) * Number.doubleValue(NumberOpp.power(base, pow - 1)));
All the code is below:
public class NumberOpp {
public static <T extends Number> T power(T base, int pow){
if (pow == 1) { /* If power is one return base */
return base;
}else{ /* Else recursivly multiply by base until power is one */
return base * NumberOpp.power(base, pow - 1);
}
}
}
You can only perform numeric operations (such as multiplication) on numeric primitive types. Number has no automatic conversion to a primitive numeric type, which is why your <T extends Number> type bound doesn't help.
You can decide to perform the operation of a specific numeric type, such as double:
public class NumberOpp {
public static <T extends Number> double power(T base, int pow) {
if (pow == 1) {
return base.doubleValue ();
} else {
return base.doubleValue () * NumberOpp.power(base, pow - 1);
}
}
}
This will accept any numeric type as input, but will always return a double result.

Java: Why would someone widen and shorten a variable?

I'm taking a java course on lynda.com, and the course was explaining how to "cast" a variable if you want to shorten it.
WIDENING: Widening a variable is making it larger (e.g. int int1 = 4030; long long1 = int1;)
SHORTENING: Shortening a variable is making it smaller, and requires special syntax. (e.g. int int2 = 5024; short int3 = (short) int2;).
So, my question is, why would anyone want to do this? What's the advantage? If you know you'll need to widen a variable at some point, why don't you just start it as that variable? And why would you want to make your data type smaller if you're shortening? If you think that it could be used like this:
byte byte1 = 127;
byte1++;
if (byte1 > 127) {
short short1 = byte1;
}
(I know that this would give an error message, but you get the rough idea.)
You could do this, but why? It wouldn't save data, because it just adds more lines of code which would take up that data.
There are several reasons you might want to "shorten" a variable.
One is that an API or library you are working with requires data to be passed that is of a "shorter" type than the type you were using in your code.
Another is to save space. For example, if I only need to store a two digit number, using a long would be overkill as it would use much more system memory than is needed. This isn't something you normally need to worry too much about, but it could be an issue on certain systems or for very large projects.
There may be even more reasons; these are just a few examples.
You absolutely can't avoid this if you must pass a value received from a function that is out of your control into another function that is also out of your control:
package abc.def:
public class Foo {
public static long foo() { ... }
}
package xyz.qwerty:
public class Bar {
public static void bar(int n) { ... }
}
Your code:
import xyz.qwerty.Bar;
import abc.def.Foo;
...
Bar.bar((int)Foo.foo());
There may be intermediate variables temporarily holding the value received from Foo.foo() before it gets to Bar.bar() but that doesn't eliminate the inevitable need for converting from one type to another, which must happen somewhere in between.
Imagine you want to implement a min(...) method to calculate the minimum of two numbers. You could simply write:
public static double min(double lhs, double rhs) {
if (lhs >= rhs) {
return (lhs);
}
// else if (rhs > lhs) {
return (rhs);
// }
and through auto-casting (or what you refer to as "widening"), you could call this method with all primitives in Java. The downside, however, is that the result would always be double and if you want to save it as an int, you would have to downcast the result:
int i1 = 0;
int i2 = 100;
int max = (int) max(i1, i2);
It would be nice if the method returned an int iff. both parameters are int, a long iff. one parapeter is long and the other parameter is long or int and so on. This would result in the following code1:
public static int min(int lhs, int rhs) {
if (lhs >= rhs) {
return (lhs);
}
// else if (rhs > lhs) {
return (rhs);
// }
}
public static long min(long lhs, long rhs) {
if (lhs >= rhs) {
return (lhs);
}
// else if (rhs > lhs) {
return (rhs);
// }
}
public static float min(float lhs, float rhs) {
if (lhs >= rhs) {
return (lhs);
}
// else if (rhs > lhs) {
return (rhs);
// }
public static double min(double lhs, double rhs) {
if (lhs >= rhs) {
return (lhs);
}
// else if (rhs > lhs) {
return (rhs);
// }
}
Then you could write:
int i = 0;
long g = 1L;
float f = 2f;
double d = 3.0;
int intMax = max(i, i);
long longMax = max(i, g);
float floatMax = max(i, f);
double doubleMax = max(l, d);
Through the means of autocasting and method overloading, the most specific method will be called2,3.
1 You culd write those methods for byte, short and charas well. I would not recommend doing so since all arithemtic operations in Java return at least something of type int (e.g. byte + byte will return an int). This is due to the fact that the JVM does not know of the primitives boolean, char, byte and short, they are represented as int (see JLS §2.11.1).
2 The exact behaviour is specified in JLS, §15.12.2.5
3 This is actually the same mechanism used forjava.lang.Math's implementation of min(...), its implementation is slightly different.

Sum of ArrayList for different types

Is it possible to write a single method total to do a sum of all elements of an ArrayList, where it is of type <Integer> or <Long>?
I cannot just write
public long total(ArrayList<Integer> list)
and
public long total(ArrayList<Long> list)
together as there will be an error of erasure, and Integer does not automatically extends to Long and vice versa... but the code inside is identical!
Yes, you can implement such a method, since both Integer and Long extend Number. For example you can use a wildcard type for the list element type:
public static long total(List<? extends Number> list) {
long sum = 0;
for (Number n : list) {
if (!(n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof Long)) {
throw new IllegalArgumentException();
}
sum += n.longValue();
}
return sum;
}
This only works for the integral types however, since the sum variable and the return value are of type long.
Ideally you would like to be able to also use the method with Floats and Doubles and return an object of the same type as the list element type, but this is not easy to do for two reasons:
The only thing you can do with a Number is to get its value as one of the primitive number types. You can not sum two of them in a number dependent way.
It is not possible to create a 0-object of the right class.
EDIT: Much later...
Just for fun, lets do this in a nice way for Java. The thing you have to do is to manually provide the two operations mentioned above. A kind of value with two such operation is usually called a monoid in the context of algebra and functional programming.
The problem can be solved by creating objects that represent the monoid operations:
interface MonoidOps<T> {
T id();
T op(T o1, T o2);
}
The total method can now be implemented to take an object of this type in addition to the list:
public static <T> T total(List<T> list, MonoidOps<T> ops) {
T sum = ops.id();
for (T e : list) {
sum = ops.op(e, sum);
}
return sum;
}
To provide MonoidOps implementations for the numeric classes, lets create a simple helper class:
class SimpleMonoidOps<T> implements MonoidOps<T> {
private final T idElem;
private final BinaryOperator<T> operation;
public SimpleMonoidOps(T idElem, BinaryOperator<T> operation) {
this.idElem = idElem;
this.operation = operation;
}
public T id() {
return idElem;
}
public T op(T o1, T o2) {
return operation.apply(o1, o2);
}
}
The MonoidOps implementations can now be written neatly like this:
static final MonoidOps<Integer> INT_MONOID_OPS = new SimpleMonoidOps<>(0, Integer::sum);
static final MonoidOps<Double> DOUBLE_MONOID_OPS = new SimpleMonoidOps<>(0.0, Double::sum);
And the total method would be called like this:
int sum = total(Arrays.asList(1, 2, 3), INT_MONOID_OPS);
You can also use streams in Java 8
public static <T extends Number> long sumList(List<T> list)
{
return list.stream().mapToLong(a -> a.longValue()).sum();
}
You can use Java´s generics for this
public <T extends Number> T total(List<T> list) {
T sum = 0;
for (T n : list) {
sum += n.longValue();
}
return sum;
}
Knowing that T will always be a Number, things are simplified. However, this solution could work also for Strings, if necessary. The only change would be in the extends part.

Java Generic Primitive type n-d array

I have to pass a primitive 2d array to a filtering routine.The algorithm for filtering(median filter) is same irrespective of the type of the array.Is there a way to pass any type of array in a generic manner or should I overload the same same function with different array types.In the second case the same code will have to be repeated for different data types.
int[][] medianfilter(int[][] arr){ ... }
float[][] medianfilter(float[][] arr){ ... }
Is there a way to make the above code a generic one,instead of repeating the code for medianfilter in each an every overloaded function ?
There is no good way to do this for primitive arrays, which is why all the library functions (such as java.util.Arrays) also have these duplicated methods.
You could define a method
Object[] medianfilter(Object[] arr); // note the missing dimension
and use reflection to find out the runtime type. This is what System.arraycopy is doing. But you then need to type-cast. Ugly.
int[][] result = (int[][]) medianFilter( input );
Go with the duplicated methods.
There is a way to pass the type of an array in a generic manner:
public T test(T[][] arg)
{
T[][] q = arg;
T[] r = q[0];
T s = r[0];
return s;
}
... unfortunately it won't work for primitive types. You'll need to use Integer and Float as your parameterized types.
The only way to pass it in a generic manner and keep it as a primitive array is as an Object. Personally, I'd just overload it, and see it as a cost of using primitives.
To avoid duplication of code in the algorithm (if it is a lot of code) you could produce an abstract class called something like DoubleAlgorithm with abstract methods like double getElement(int i, int j) and handleResult(double result) and then write very small subclasses of this, one for each primitive type.
Let me explain with an example (suppose the algorithm was adding the numbers).
public int filter(int [][] values) {
IntAlgorithm algo = new IntAlgorithm(values);
algo.run();
return algo.getResult();
}
public double filter(double [][] values) {
DoubleAlgorithm algo = new DoubleAlgorithm(values);
algo.run();
return algo.getResult();
}
public class AbstractAlgorithm {
public run() {
double sum = 0.0;
for(int i=0; i<rows(); i++) {
for(int j=0; j<columns(i); j++) {
sum+=getElement(i, j);
}
}
handleResult(sum);
}
protected abstract int rows();
protected abstract int columns(int row);
protected abstract double getElement(int i, int j);
protected abstract void handleResult();
}
public class IntAlgorithm extends AbstractAlgorithm {
int [][] values;
int result;
IntAlgorithm(int [][] values) {
this.values= values;
}
public int rows() {
return values.length;
}
public int columns(int row) {
return values[row].length;
}
public double getElement(int i, int j) {
return values[i][j];
}
public void handleResult(double result) {
this.result = (int)result;
}
public int getResult() {
return result;
}
}
As you can see, it is quite verbose, but if your algorithm was big it might be worth it. Hopefully it is obvious how to extend to your algorithm.
As Thilo has pointed out, it isn't safe to do all algorithms with just treating ints/longs as doubles, but for a number it will be good enough. If it isn't for you, then you need to go even more verbose, work out which properties of numbers you need (eg add) and extract those to a separate interface. For a median filter, I would expect just using doubles will work fine, but I'd test the edge cases.

Categories