Reputation: 2016
Can you please help me explain a warning in a generic method? I came across this Oracle tutorial task and tried to implement it:
Write a generic method to find the maximal element in the range [begin, end) of a list.
Here is my first version that works well but compiles with a warning:
Information:java: C:\Java\bla\bla uses unchecked or unsafe operations.
public static <T extends Comparable> T findMax2(List<T> list, int first, int second) {
T max = list.get(first);
for (int i = first+1; i < second; i++) {
if (list.get(i).compareTo(max)>0) max = list.get(i);
}
return max;
}
Then I snooped Collections.max method and rewrote my method this way (now it compiles without any warning and works just as well!):
public static <T extends Object & Comparable<? super T>> T findMax3(List<T> list, int first, int second) {
T max = list.get(first);
for (int i = first+1; i < second; i++) {
if (list.get(i).compareTo(max)>0) max = list.get(i);
}
return max;
}
The question is why? What's wrong with my first attempt method? And why does the improved version fixes the warning?
Upvotes: 0
Views: 589
Reputation: 9093
When you compile without proper generics you should get both these messages:
Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
If you recompile with -Xlint
, it will tell you where the unsafe operation is, and the raw type that led to it:
>> javac -Xlint Test.java
Test.java:17: warning: [rawtypes] found raw type: Comparable
public static <T extends Comparable> T findMax2(List<T> list, int first, int second) {
^
missing type arguments for generic class Comparable<T>
where T is a type-variable:
T extends Object declared in interface Comparable
Test.java:20: warning: [unchecked] unchecked call to compareTo(T) as a member of the raw type Comparable
if (list.get(i).compareTo(max)>0) max = list.get(i);
^
where T is a type-variable:
T extends Object declared in interface Comparable
2 warnings
public class Fake implements Comparable<Integer>{
public int compareTo(Integer i){
return i.compareTo(1);
}
public static <T extends Comparable> T findMax2(List<T> list, int first, int second) {
T max = list.get(first);
for (int i = first+1; i < second; i++) {
if (list.get(i).compareTo(max)>0) max = list.get(i);
}
return max;
}
public static void main(String[] args){
Fake fake = new Fake();
List<Comparable<Integer>> l = new ArrayList<>();
l.add(fake);
l.add(1);
l.add(3);
l.add(6);
findMax2(l, 0, l.size()-1);
}
}
Exception in thread "main" java.lang.ClassCastException: Fake cannot be cast to java.lang.Integer at java.lang.Integer.compareTo(Integer.java:52) at Fake.findMax2(Fake.java:12) at Fake.main(Fake.java:24)
This example relies on someone making a strange class that is Comparable
to a totally unrelated class, but as you can see, with your notation, it is possible to get an exception if this strange class is used along with the class it can be compared to.
Upvotes: 2