I keep getting a message telling me that the operator < is undefined for the types T,T. This is happening around
if(index<lowest)
How would I go about modifying my program so that I could get the smallest and largest values of an array list using a generic method?
package p07;
import java.util.ArrayList;
public class MyList<T extends Number> {
private ArrayList<T> l;
public MyList(ArrayList<T> l) {
this.l=l;
}
public void add(T x) {
l.add(x);
}
public static <T> void smallest(ArrayList<T> l) {
T lowest=l.get(0);
for(T index:l) {
if(index<lowest) {
}
}
}
}
The compiler is right: the operator < is only applicable to primitive numeric type. Quoting section 15.20.1 of the JLS:
The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.
Hence, it is not defined for Objects, not even for Numbers, because they cannot be unboxed to a primitive type: section 5.1.8 of the JLS:
A type is said to be convertible to a numeric type if it is a numeric type (§4.2), or it is a reference type that may be converted to a numeric type by unboxing conversion.
What you need is to use a Comparator or make your objects Comparable. Comparators are responsible for comparing two objects of the same type. Since the objects here are Numbers, and they are not Comparable, you need to use a custom Comparator, like this:
Comparator<Number> myComparator = new Comparator<Number>() {
#Override
public int compareTo(Number n1, Number n2) {
// implement logic here.
// Return -1 if n1 < n2, 0 if n1 = n2, 1 if n1 > n2
}
};
Then you can use this comparator like this:
public static <T extends Number> T smallest(List<T> l) {
T lowest = l.get(0);
for (T index : l) {
if (myComparator.compareTo(index, lowest) < 0) {
index = lowest;
}
}
return lowest;
}
(Note that I added T extends Number to the type of the method - that is because the method is static so it's in fact declaring another type T that the one the class is).
There are several things awry here, but let's start with the low-hanging syntax fruit.
The arithmetic operators only work for primitive values, and T is very much an Object, so you wouldn't be able to use them here.
Another nuance to your syntax is that you're T for that static function is not the same as the T which is bound to your class.
You can fix that, either by adding the bound yourself...
public static <T extends Number> void smallest(ArrayList<T> l)
...but this leads me to ask, why would you want this method to be static at all?
You're obscuring the name of the field l with the parameter l, so while you may think that this is going to work for the instance's provided l, it won't since the method itself is declared static, and you'd still be shadowing the field's name if it weren't.
What you should do is remove static from that method, and remove the parameter from the function.
public void smallest() {}
But now, you've got an issue in that you don't actually return what the smallest value is. You should return it instead of nothing:
public T smallest() {}
Getting the last value out of an array is straightforward if you're capable of sorting. You just need to ensure that all of your elements are Comparable so that they can be sorted, and the values you care about the most - like Integer, Double, Float, Long - are.
public class MyList<T extends Number & Comparable<T>> {}
If you can sort, then getting the smallest is straightforward:
public T smallest() {
// Don't mutate the order of the original array.
ArrayList<T> listCopy = new ArrayList<>(l);
Collections.sort(listCopy);
return listCopy.get(0);
}
Getting the highest via this approach I leave as an exercise for the reader.
Related
In the code below Comparable interface is used to ensure x and y should be of same reference type but as V is extending T so V should be of the same type as T or subclass of T then what is the point of using Comparable interface.
Also if I am not using Comparable interface then the last call to isIf method is getting compile despite x and y are of different types.
Can anyone explain the use Comparable interface regarding this program?
public class Generics_13 {
static <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y) {
for(int i = 0;i < y.length;i++)
if(x.equals(y[i])) return true;
return false;
}
public static void main(String[] args) {
Integer nums[] = {10, 20, 30};
if(isIn(10, nums))
System.out.println("10 belongs to the array");
if(!isIn(60, nums))
System.out.println("70 doesnt belong to the array");
String arr[] = {"Neeraj", "Parth", "Ritum"};
if(!isIn("abc", arr))
System.out.println("abc doesnt belongs to the array");
/*if(isIn("String", nums)) // illegal
System.out.println("This wont compile");
*/
}
}
The current use of generics doesn't really makes sense, because no method from Comparable is ever used, which means that you could simply remove the extends declaration.
Also the Type V is also not used, as you can simply replace it by T and not break your logic. so the final result would look like this:
public class Generics_13 {
static <T> boolean isIn(T x, T[] y) {
for(int i = 0;i < y.length;i++)
if(x.equals(y[i])) return true;
return false;
}
// main() etc follow here
}
But now that we have the Stream API in java-8 you can use the following snippet to achieve the same thing:
static <T> boolean isIn(T x, T[] y) {
return Arrays.stream(y).anyMatch(i -> i.equals(x));
}
The comparable here in your scenario is optional.
T extends Comparable<T>
What this means is that whatever value you are passing should implement the interface comparable.
which basically means that the type parameter can be compared with other instances of the same type.
Now you might be wondering that since you are passing primitive data types, then how does the code not throw an error?
The reason for this is that the primitives are autoboxed to wrapper objects which implement Comparable.
So your ints become Integer and String is already an object both of which implement Comparable.
PS : your code will also work for objects provided that the class implements comparable
I am trying to create a generic class in Java that will perform operations on numbers. In the following example, addition, as follows:
public class Example <T extends Number> {
public T add(T a, T b){
return a + b;
}
}
Forgive my naivety as I am relatively new to Java Generics. This code fails to compile with the error:
The operator + is undefined for the argument type(s) T, T
I thought that with the addition of "extends Number" the code would compile. Is it possible to do this Java or will I have to create overridden methods for each Number type?
Number does not have a + operator associated with it, nor can it since there is no operator overloading.
It would be nice though.
Basically, you are asking java to autobox a descedant of Number which happens to include Integer, Float and Double, that could be autoboxed and have a plus operator applied, however, there could be any number of other unknown descendants of Number that cannot be autoboxed, and this cannot be known until runtime. (Damn erasure)
Your problem is not really related to generics, rather to operators, primitives vs objects, and autoboxing.
Think about this:
public static void main(String[] args) {
Number a = new Integer(2);
Number b = new Integer(3);
Number c = a + b;
}
The above does not compile
public static void main(String[] args) {
Integer a = new Integer(2);
Integer b = new Integer(3);
Number c = a + b;
}
The above does compile, but only because of autoboxing - which is kind of a hacky syntax glue introduced in Java 5, and only works (in compile time) with some concrete types : int-Integer for example.
Behind the scenes, the Java compiler is rewriting the last statement ("I must unbox a and b to apply the sum operator with primitive datatypes, and box the result to assign it to object c") thus:
Number c = Integer.valueOf( a.intValue() + b.intValue() );
Java can't unbox a Number because it does not know at compile time the concrete type and hence it cannot guess its primitive counterpart.
You can do something like this
class Example <T extends Number> {
public Number add(T a, T b){
return new Double(a.doubleValue() + b.doubleValue());
}
}
Yes, Nathan is correct. If you want something like this, you have to write it yourself
public class Example <T extends Number> {
private final Calculator<T> calc;
public Example(Calculator<T> calc) {
this.calc = calc;
}
public T add(T a, T b){
return calc.add(a,b);
}
}
public interface Calculator<T extends Number> {
public T add(T a, T b);
}
public class IntCalc implements Calculator<Integer> {
public final static IntCalc INSTANCE = new IntCalc();
private IntCalc(){}
public Integer add(Integer a, Integer b) { return a + b; }
}
...
Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));
Too bad Java has no type classes (Haskell) or implicit objects (Scala), this task would be a perfect use case...
There are similar questions to this one, and the answer is you can't do it like that.
You could check if a and b are an instance of Long/Double/Integer/etc. and delegate the add to methods like:
public Integer add(Integer a, Integer b) {
return a+b; // this actually uses auto boxing and unboxing to int
}
And you would need to create one for every type that extends Number, so that's not really feasible. In other words, don't use generics for numeric operations. Number as a superclass is pretty limited.
Consider Example<Number>, how would + work on that? There is no add or similar in Number or even the likes of Integer.
Worse consider final class FunkyNumber extends Number { ... weird stuff, no add op ... }.
Even the java runtime library has this problem, most of the methods dealing with primitives have to duplicate the same functionality.
The fastest option would be to write your code for one type and then copy it and replace the type to generate the methods for the other types. A short script should be enough to do this.
If I have a class that uses a template <T> how do I compare two variables of type T? One of my friends told me that you should add <T extends Comparable<? super T>> to your class in order to compare type T variables, but I dont competely understand what he ment. Here is my class:
public class SomeClass<T extends Comparable<? super T>>
{
public SomeClass(){}
public T foo(T par, T value)
{
if(value > par)
{
return value
}
else
{
return par;
}
}
}
And in my Main.java:
SomeClass<Integer> sc = new SomeClass<Integer>();
Integer val1 = 10;
Integer val2 = 5;
System.out.println(sc.foo(val1, val2));
The error i get is:
error: bad operand types for binary operator '>' if(value > par)
Your T implements Comparable, so you should use its compareTo() method.
if (value.compareTo(par) > 0) {
....
}
Also, note that in java it is called Generics, and not Templates, and is quite different from C++ templates (much weaker and much less complicated from the C++ version). One important difference is it does not work on primitives, only on objects - so if you wanted to use SomeClass<int> - that's impossible. (You could use SomeClass<Integer> however).
Also note, you cannot assign
T = 0;
Since T is an object.
> operator can be used only on primitives and not on objects. You need to use compareTo method for comparing objects.
I didn't even know this was doable, but I saw while perusing some code online a method with a signature like this:
public List<Void> read( ... )
... What? Is there ever a reason to do this? What could this List even hold? As far as I was aware, it's not possible to instantiate a Void object.
It is possible that this method signature was created as a by-product of some generic class.
For example, SwingWorker has two type parameters, one for final result and one for intermediate results. If you just don't want to use any intermediate results, you pass Void as the type parameter, resulting in some methods returning Void - i.e. nothing.
If there were a method List<V> returnAllIntermediateResults() in SwingWorker with Void as the type parameter V, it would have created a method just like you posted in your question.
The code would be perfectly valid. You can instantiate any implementation of the List interface (e.g. ArrayList) with type parameter Void. But the only value a Void type can have is null. So the list could not hold anything else but nulls, if the implementation allows null elements.
One case in which it may be useful is if you wanted to return a collection of return values from a function. Say
static List<T> forEach(Func<A,T> func, List<A> items) {
List<T> ret = new List<T>();
for(int i = 0; i< items.length; i++) {
ret.add(func.call(items[i]);
}
return ret;
}
public static void main() {
...
List<Void> boringResult =
forEach(
new Func<Void, Integer> {#override Void call(Integer i) {...}});
}
Not that useful but you could see a case where it was required.
List<Void> is weird. It can only have null elements, since you can't create an object of type Void. I don't think there is a practical use for such a thing.
Void is part of java.lang. It's not a special keyword or anything. It's a "pseudo-type" (according to the docs) used to as a place-holder to represent the Class object corresponding to void, as in Class<Void>. From the docs for Class:
The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
The Void class exists mainly for the sake of the last part of this, so you can write:
Class<Void> voidType = void.class; // == Void.TYPE
just like you can write:
Class<Integer> intType = int.class; // == Integer.TYPE
I agree, it's odd.
I can see a use for it if you want to extend a generic class and return void from a method. I've bumped into a case were I want to use int and had to use Integer because java generics don't like primitive types.
public interface ObjectUserPool<E, T> {
public E useObject(T o);
}
public class NonReturningObjectUserPool extends ObjectUserPool<Void, Integer> {
public Void useObject(Integer i);
}
I think this is what the java API is saying, though to be honest I can't really find a use for NonReturningObjectUserPool.
public class Calculator<T> {
public Calculator(){
}
public T calculateSum(T a,T b){
return a; // I need to do something like a + b
}
}
I need to add the T object, I'm restricting the T to be only numeric types. How can I do this?
Thanks
Generic type arguments must be reference types, which excludes arithmetic types. You can give a boxed type such as Integer as the type argument, but that will not let you do arithmetic because auto-unboxing only works for particular, specific boxed types. Even if you restricted the type parameter to be a descendant of Number, there would be no way the compiler could be sure that the actual type argument was not some user-defined subclass of Number that did not have any auto-unboxing behavior.
More technically, generic types will not let you do anything that you wouldn't be able to achieve by inserting downcasts (and nothing else) in non-generic code. Here, it looks like you want to have a different kind of addition (integer or floating-point) depending on which type the argument is. And there is no way to achieve that solely by inserting casts; you'd have to insert some explicit condition that tested if the values happen to be Integer, then Long, then Float, et cetera. Since this is more complex than a downcast here or there, generics cannot, in principle, to this for you.
This is different from C++ templates, where each instantiation of the template generates (in principle, at least) a separate implementation in the compiler.
What you can do is make Calculator<T> an abstract class or an interface. Then make concrete subtypes such as
public class IntCalculator extends Calculator<Integer> {
public Integer calculateSum(Integer a, Integer b) {
return a+b;
}
}
public class DoubleCalculator extends Calculator<Double> {
public Double calculateSum(Double a, Double b) {
return a+b;
}
}
and so forth.
Methods (as well as classes) can have type parameters.
public class Calculator {
public Calculator(){
}
public <T extends Number > T calculateSum(T a,T b){
return a; // I need to do something like a + b
} }
Generics are not needed for this exercise.
public class Calculator {
public Calculator(){
}
public int calculateSum(int a,int b){
return a + b ;
}
public long calculateSum(long a,long b){
return a + b ;
}
.... you fill in the rest ...
}
In your declaration you need to make sure that T is always a sub-type of Number.
Instead of
Calculator<T>
try
Calculator<T extends Number>
then look in java.lang.Number and you should find a way to get a value that works with +.