1

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) { 

            }
        }   
    }
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Matt
  • 73
  • 11

2 Answers2

-1

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).

Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • The problem is that the question I'm trying to do only wants me to constrain the program to the upper bound of Numbers – Matt Oct 11 '15 at 17:59
  • @Matt You need to implement a `Comparator`, like the one I mentioned in my answer. – Tunaki Oct 11 '15 at 18:05
  • Thank you for your help. I just remembered that methods can implements the Comparable inteface – Matt Oct 11 '15 at 18:06
  • I actually have one more question. If I want to use a toString method to print each element of the array list, how would I go about doing that? – Matt Oct 11 '15 at 18:36
  • @Matt You can simply use `toString` on the list itself. It will print every element. – Tunaki Oct 11 '15 at 18:45
  • But what if I wanted to print 5 elements of the array list to a line? – Matt Oct 11 '15 at 19:06
  • You don't really need a custom comparator in this scenario. If you can guarantee that you're only ever inserting `Number`s, then you can leverage the `Comparable` interface on the `Number` class directly. – Makoto Oct 11 '15 at 19:09
  • @Makoto [`Number` does not implement `Comparable`](http://stackoverflow.com/q/480632/1743880). I'm not sure how `Comparable` could be used here. – Tunaki Oct 11 '15 at 19:15
  • Ah, slip of the tongue there. `Number` doesn't implement `Comparable`, but most every child class of it *does*. I'll finish writing it up here in a second. – Makoto Oct 11 '15 at 19:16
  • @Makoto Well not if I do `class Fraction extends Number`. How can then a `Fraction` be compared using `Comparable`? – Tunaki Oct 11 '15 at 19:18
  • You'd want to implement `Comparable` on `Fraction`, then. It doesn't make sense to have a list of `Number`s which can't be rationally ordered; how on Earth would you be able to pick out which one is larger than the other?! – Makoto Oct 11 '15 at 19:18
  • @Makoto In this question, we only have `T extends Number` so I don't see how can assume that `T` is also `Comparable`. Like I said in my answer, you need to implement your business logic inside a `Comparator` (for example comparing `doubleValue`). It needs to work regardless of the `Number` implementation. The question of _when_ is a `Number` a bigger than a `Number` b is up to the OP (he hasn't stated what it should be but I assume there is one) – Tunaki Oct 11 '15 at 19:20
-1

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.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • This is wrong. We can't assume that the `Number` the OP has are `Comparable`. Maybe he wants to compare `class Fraction extends Number` and he can't change `Fraction`. – Tunaki Oct 11 '15 at 19:28
  • Fundamentally it doesn't make sense to have a `Number` which isn't `Comparable`, but we'll have to see what the requirements actually are. There's still a lot of ambiguity and confusion as to why the function was static to begin with, as well as what `Number` they're actually implementing. I strongly doubt they're using any custom `Number` classes - this seems like a straightforward assignment - so unless the OP actually does say they're using that, then I wouldn't be so quick to say that this is "wrong". – Makoto Oct 11 '15 at 19:30
  • If it didn't make sense for a `Number` not to be `Comparable` then `Number` would implement `Comparable`. It seems you don't agree with how this class was designed. There is no ambiguity in the question (apart from the whole static thing which is probably a typo): `T extends Number`, that's all. – Tunaki Oct 11 '15 at 19:34