Collections.sort no compile time error - java

What is the difference between Collections.sort(list) and Collections.sort(list,null)
I supposed both of them compared elements in the list in their natural order.
So I tried these two codes:
CODE 1:
List<Object> list=Arrays.asList("hello",123);
Collections.sort(list);
CODE 2:
List<Object> list=Arrays.asList("hello",123);
Collections.sort(list,null);
The latter compiles but former doesn't giving the expected compiler error that instances of class Object are not comparable.
Why latter does not give compile time error.
EDIT: Based on the comment given below. I understand why latter doesn't give compile time error but on running it throws ClassCastException : String cannot be converted into Integer . How it deduced that runtime objects are String and Integer because what I think
public static sort(List<Object> list) ---> Since list was of type object
{
// For instances of object in list call the compareTo method
}
}

Java's generic types are checked at compile time. If you violate the constraits, you can't even compile. The first method is defined as:
<T extends Comparable<? super T>> void sort(List<T> list)
That requires that the List you use is of a type that extend Comparable, specifically some Comparable<X> where X may be any superclass of T. Sounds complicated but doesn't even matter here (try understanding http://yzaslavs.blogspot.de/2010/07/generics-pecs-principle-step-by-step.html if you're interested in that part). List<Object> does not match the first part already. Object doesn't implement any Comparable. => Compiler says no.
The second one is defined as
<T> void sort(List<T> list, Comparator<? super T> c)
that no longer requires that the type of the List has any special property. Any T will work. The only requirement is that you can provide an implementation of Comparator that is able to sort T or a super type. null is like a joker and fits anything. The compiler will not complain even if using null is probably wrong. You do see the problem at runtime.
The reason for
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.lang.Integer.compareTo(Integer.java:52)
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:157)
at java.util.Arrays.sort(Arrays.java:537)
at java.util.TimSort.sort(TimSort.java:178)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at Main.main(Main.java:9)
is that at "TimSort.java:178" it does
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c) {
if (c == null) {
Arrays.sort(a, lo, hi);
return;
}
which falls back to natural sorting like your first call would do. However it's just a Object[] array at that point and nothing can guarantee that types are actually comparable. It simply casts the types and that fails depending on your luck & content of the list either in Integer.compareTo( ) or String.compareTo( ) because those methods require their own type.

These are two different methods in Collections
//here the elements in list should impl. Comparable
Collections.sort(list)
//here we need a Comparator object, (null is Comparator obj too)
Collections.sort(list, null)
Now comes to the question of runtime classcast problem.
Java converts your list into array to do the sort in background. If your Comparator is null, java will cast the element to Comparable to do sort. Fortunately, the two elements in your list both (String and Integer) implemented Comparable. so till here no Exception.
You have only two elements (2<7 7 is the insertionsort threshold) in your list, so java just simply do insertion sort. Take the Integer, and call the compareTo() method with your string as parameter. Here java cast the parameter to Integer, so that it can compare. As you've seen, String cannot be cast to Integer, you got that Exception.

There is no difference between these two, Is clearly mentioned in api doc.
Refer Collections

> what is null?
According to JSL -
There is also a special null type, the type of the expression null,
which has no name. Because the null type has no name, it is impossible
to declare a variable of the null type or to cast to the null type.
The null reference is the only possible value of an expression of null
type. The null reference can always be cast to any reference type. In
practice, the programmer can ignore the null type and just pretend
that null is merely a special literal that can be of any reference
type.
As null can be reference of any type so it can be reference of Comparator as well, That is why compiler accepts Collections.sort(list,null);.
Where as Collections.sort(list,new Object()); gives compile time exception.
At the time of comparison check compareTo Method will be called Where in Integer.compareTo method it generate ClassCastException.

Related

generics benefit when we can use parent object

I have learned that in compile time generics we use changes to most specific type. so what is the benefit of generics?
for example in this code:
int a=1;
double b = 2.1;
printArray(a,b);
public static <E> void printArray(E first , E second);
in compile time E changes to Number (because the specific parent of int and double is Number)
so what is the benefit of generics when we can write Number instead of E in here?
The purpose of generics is not related to the fact that the generic parameter will be inferred to be the most specific type. The purpose of generic methods is to allow you to write a method that can work with any type and at the same time, maintain type safety.
Your printArray method can not only take Number as arguments, but also String, SomeClass, Object and all sorts of reference types.
At this point you might ask "can't we just write Object as the parameter types?" Sure with the type being Object, the parameter will not only accept all reference types, but the primitives will also be accepted and boxed! So in this specific case, you don't necessarily have to use a generic method.
However, there are times when generic methods shine.
One of these occasions is when the methods work with generic types. For example, this is Optional.ofNullable:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
It creates a Nullable<T> depending on whether the parameter is null. If this were not generic, it would have to return Optional<Object>. Every time you want to call get or orElse, you need to cast the result to the type you want. If you made a mistake in one of the casts, a ClassCastException might be thrown at runtime. But with generics, the compiler checks the types for you!
Here's another example:
public static <T> T first(List<T> list) { return list.get(0); }
Without generics, you would have to use the raw type List and return an Object. This again creates the problems of casting and reduced type safety.

Lower-Bounded Wildcards Java - Access to Methods

I understand that one reason Lower-bounded wildcards exist is so that a collection is not immutable when adding new elements.
E.g.
List<? extends Number> obj = new ArrayList<>();//Now this list is immutable
obj.add(new Integer(5));//Does not compile
List<? super Number> objTwo = new ArrayList<>();//This list is mutable
objTwo.add(new Integer(5));//Compiles
The following does not compile because I tried to get the long value of numbers.
Q1: What methods would I be able to use? Only Objects methods?:
public void testLowerBounds(List<? super Number> numbers){
if (!numbers.isEmpty()){
System.out.println(numbers.get(0).longValue());//Does not compile
}
}
How my question came about:
I am currently learning about streams and the book specifies the following stream method:
Optional<T> min(Comparator<? super T> comparator)
And implements it as follows:
Stream<String> s = Stream.of("monkey", "ape", "bonobo");
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length());
Q2: How is the comparator allowed to use string methods when is used?
If I had to answer Q2: I would say that optional is specifying "You have to pass me an implementation of Comparator that has a generic type "String" or something that implements "String". Would I be correct in saying this?
Looking forward to your response.
First of all, you should not confuse wildcard type parameters with mutability. Having a wildcard in a List’s element type does not prevent modifications, it only imposes a few practical restrictions to what you can do with the list.
Having a list declared like List<? extends Number> implies that the referenced list has an actual element type of Number or a subclass of Number, e.g. it could be a List<Integer> or List<Double>. So you can’t add an arbitrary Number instance as you can’t know whether it is compatible to the actual element type.
But you can still add null, as the null reference is known to be compatible with all reference types. Further, you can always remove elements from a list, e.g. call remove or clear without problems. You can also call methods like Collections.swap(list, index1, index2), which is interesting as it wouldn’t be legal to call list.set(index1, list.get(index2)) due to formal rules regarding wildcard types, but passing the list to another method that might use a non-wildcard type variable to represent the list’s element type works. It’s obviously correct, as it only sets elements stemming from the same list, which must be compatible.
Likewise, if you have a Comparator<Number>, you can call Collections.sort(list, comparator), as a comparator which can handle arbitrary numbers, will be able to handle whatever numbers are actually stored in the list.
To sum it up, having ? extends in a collection’s element type does not prevent modifications.
As said, you can’t insert arbitrary new elements into a list whose actual element type might be an unknown subclass of the bound, like with List<? extends Number>. But you are guaranteed to get a Number instance when retrieving an element, as every instance of subtype of Number is also an instance of Number. When you declare a List<? super Number>, its actual element type might be Number or a super type of Number, e.g. Object or Serializable. You can insert arbitrary Number instances, as you know it will be compatible to whatever actual element type the list has, as it is a super type of number. When you retrieve an instance, you only know that it is an instance of Object, as that’s the super type of all instances. To compare with the ? extends case, having a ? super declaration does not prevent reading, it only imposes some practical limitations. And likewise, you can still pass it to Collections.swap, because, regardless of how little we known about the actual type, inserting what we just retrieved from the same list, works.
In your second question, you are confusing the sides. You are now not looking at the implementation of min, but at the caller. The declaration of min(Comparator<? super T> c) allows the caller to pass any comparator being parameterized with T or a super type of T. So when you have a Stream<String>, it is valid to pass a Comparator<String> to the min method, which is exactly, what you are implementing via the (s1, s2) -> s1.length()—s2.length() lambda expression (though, I’d prefer Comparator.comparingInt(String::length)).
Within the implementation of min, there is indeed no knowledge about what either, T or the actual type argument of the Comparator, is. But it’s sufficient to know that any stream element that is of type T can be passed to the comparator’s compare method, which might expect T or a super type of T.

Understanding Collections.reverseOrder() method in Java

Consider one of the overloaded definitions of sort method from Array class:
public static <T> void sort(T[] a, Comparator<? super T> c)
A common way to sort array in reverse order is to pass Comparator returned by Collections.reverseOrder() as a second argument to this method.
Let's look at the implementation of Collections.reverseOrder() method from openjdk 7:
public static <T> Comparator<T> reverseOrder() {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
}
ReverseComparator class:
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER = new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return reverseOrder(); }
}
My question is: why Collections.reverseOrder() is made to be generic? And why simply ReverseComparator.REVERSE_ORDER can't be returned?
Of course, we can specify type explicitly calling Collections.<T>reverseOrder(). But what's the benefit against simple Collections.reverseOrder() in this case?
I found a rather useful discussion there:
How does Collections.reverseOrder() know what type parameter to use?
But it doesn't answer to my question.
Also It's interesting for me how sort method uses compare method from ReverseComparator class. As we can see compare takes arguments of Comparable<Object> type. And what if we sort array of objects implementing Comparable<T>, where T is for example Integer? We can't invoke compare with Comparable<Integer> cause Comparable<Integer> isn't casted to Comparable<Object>.
why Collections.reverseOrder() is made to be generic?
This function is generic so as to spare you from having to cast the result into your specific Comparable<T> type. (You might say that you don't care because you don't cast it anyway, in which case what this tells us is that you do not have enough warnings enabled.)
why we can't simply return ReverseComparator.REVERSE_ORDER?
One reason is because ReverseComparator.REVERSE_ORDER is package-private, so you cannot access it from outside that package. Which in turn begs the question "why is it package-private?" Well, mainly because this satisfies the purists who cringe when they see member variables being directly accessed even if they are final, but actually I would not blame them in this case, because accessors offer forward compatibility at the binary level, which might be completely unnecessary in application code, but it kind of becomes a necessity in a language runtime. And ReverseComparator is part of the java runtime.
But a more important reason is because Collections.reverseOrder() does the cast to (Comparator<T>) for you, so that you don't have to do it yourself. (Again, if you don't see a problem with this, that's because you do not have enough warnings enabled, which means you need to reconsider your practices.)
In short, if you tried to do the following:
Comparator<MyObject> myComparator = ReverseComparator.REVERSE_ORDER;
you would get an error, because this is an invalid assignment. So, you would have to change it to this:
Comparator<MyObject> myComparator =
(Comparator<MyObject>)ReverseComparator.REVERSE_ORDER;
but then you would get a warning, because this is an unchecked cast. So you would end up having to do this:
#SuppressWarnings( "unchecked" )
Comparator<MyObject> myComparator =
(Comparator<MyObject>)ReverseComparator.REVERSE_ORDER;
which is ugly. So, Collections.reverseOrder() saves you from that, allowing you to do this:
Comparator<MyObject> myComparator = Collections.reverseOrder();
As we can see compare takes arguments of Comparable type. And what if we sort array of objects implementing Comparable, where T is for example Integer? We can't invoke compare with Comparable cause Comparable isn't casted to Comparable.
Okay, I see what your real question is. Welcome to the wonderful world of java generics and type erasure. I will try to explain, but be sure to also look up the term "type erasure" in order to fully understand the concept.
In java, generics were introduced to the language as an afterthought. For this reason, they had to be implemented in such a way that generics-aware code would be backwards compatible with old code which was not generics-aware. The solution was a trick called type erasure, which basically means that generic information is completely stripped after compilation. This means that at the bytecode level, Comparator<String> and Comparator<Integer> and Comparator are one and the same thing. No difference whatsoever. This is what enables the java runtime to implement a single class which acts as a reverse comparator of any object. It is not really a Comparator<Object>, it is a Comparator<ANYTHING>, because all it does is reverse the direction of the comparison, so it does not really care about the nature of the objects that are being compared.
So, in java, if you really know what you are doing, you are free to cast an instance of a generic class to an instance of the same class, but with a different generic parameter. In this case, the creators of the java runtime are casting Comparator<Object> to Comparator<T>, which may in fact be later assigned to Comparator<Integer>, and that's fine.
This cast is tricky though, because the compiler has to trust that you really know what you are doing, so by default, the compiler issues an "unchecked assignment" warning on such casts, and then in turn we indicate that we swear we know what we are doing with a #SuppressWarnings( "unchecked" ) annotation.
Collections.reverseOrder() spares you from having to be concerned with all that.
This is all about type erasure. Remember, at runtime there is no such thing as a Comparable<Object>, there is only such a thing as a Comparable. Therefore the compare method of REVERSE_COMPARATOR works on two String instances, for example. It doesn't cause a ClassCastException at runtime because String implements Comparable<String>, and at runtime that's just Comparable.
However, the method reverseComparator has to be generic, because otherwise the user would have to cast the returned object to the appropriate type before it could be used. For example, consider this code where the comparator has the same type as the declared type of REVERSE_COMPARATOR.
Comparator<Comparable<Object>> comparator = Collections.reverseOrder();
String[] arr = {"A", "B", "C"};
Arrays.sort(arr, comparator); // Doesn't compile.
The reason this doesn't compile is because arr is a String array, and so Arrays.sort expects a Comparator<? super String>, but Comparable<Object> is not a supertype of Comparable<String> (Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?).
You can make it compile by using casts:
Comparator<Comparable<Object>> comparator = Collections.reverseOrder();
String[] arr = {"A", "B", "C"};
Arrays.sort(arr, (Comparator<String>) (Object) comparator);
System.out.println(Arrays.toString(arr)); // prints [C, B, A]
This generates a warning, but as you will see it you try it, it works. By using a generic method, the ugliness of the cast and the warning is kept out of the code using the method.
The fact that the same object (REVERSE_COMPARATOR) can be treated as being a Comparator<String> or a Comparator<Integer>, or a Comparator<X> where X is any type implementing Comparable is one of the many benefits of type erasure. This reuse of objects is not possible in C# because in C# instances of a generic class know the type.
There are many examples of this kind of reuse. For example, all of these generic methods always return the same instance, no matter what generic type you supply.
Collections.emptySet()
Optional.empty()
Comparator.naturalOrder()
Collections.emptyListIterator()

Should remove(Object) be remove(? super E)

In this answer, I tried to explain why the Collection method add has the signature add(E) while remove is remove(Object). I came up with the idea that the correct signature should be
public boolean remove(? super E element)
And since this is invalid syntax in Java, they had to stick to Object, which just happens to be super E (supertype of E) for any E. The following code explains why this makes sense:
List<String> strings = new ArrayList();
strings.add("abc");
Object o = "abc"; // runtime type is String
strings.remove(o);
Since the runtime type is String, this succeeds. If the signature were remove(E), this would cause an error at compile-time but not at runtime, which makes no sense. However, the following should raise an error at compile time, because the operation is bound to fail because of its types, which are known at compile-time:
strings.remove(1);
The remove takes an Integer as an argument, which is not super String, which means it could never actually remove anything from the collection.
If the remove method was defined with the parameter type ? super E, situations like the above could be detected by the compiler.
Question:
Am I correct with my theory that remove should have a contravariant ? super E parameter instead of Object, so that type mismatches as shown in the above example can be filtered out by the compiler? And is it correct that the creators of the Java Collections Framework chose to use Object instead of ? super E because ? super E would cause a syntax error, and instead of complicating the generic system they simply agreed to use Object instead of super?
Also, should the signature for removeAll be
public boolean removeAll(Collection<? super E> collection)
Note that I do not want to know why the signature is not remove(E), which is asked and explained in this question. I want to know if remove should be contravariant (remove(? super E)), while remove(E) represents covariance.
One example where this does not work would be the following:
List<Number> nums = new ArrayList();
nums.add(1);
nums.remove(1); // fails here - Integer is not super Number
Rethinking my signature, it should actually allow sub- and supertypes of E.
This is a faulty assumption:
because the operation is bound to fail because of its types, which are known at compile-time
It's the same reasoning that .equals accepts an object: objects don't necessarily need to have the same class in order to be equal. Consider this example with different subtypes of List, as pointed out in the question #Joe linked:
List<ArrayList<?>> arrayLists = new ArrayList<>();
arrayLists.add(new ArrayList<>());
LinkedList<?> emptyLinkedList = new LinkedList<>();
arrayLists.remove(emptyLinkedList); // removes the empty ArrayList and returns true
This would not be possible with the signature you proposed.
remove(? super E) is entirely equivalent to remove(Object), because Object is itself a supertype of E, and all objects extend Object.
I think that designers of the collections framework made a decision to keep remove untyped, because it is a valid solution that lets you keep a post-condition without introducing a pre-condition or compromising type safety.
The post-condition of a c.remove(x) is that after the call x is not present in c. Method signature remove(Object) lets you pass any object or null, with no further checks. Method signature ? super E, on the other hand, introduces a pre-condition on the type of x, requiring it to be related to E.
Each pre-condition that you introduce in an API makes your API harder to use. If removing a pre-condition lets you keep all your post-conditions, it is a good idea to remove the pre-condition.
Note that removing an object of a wrong type is not necessarily an error. Here is a small example:
class Segregator {
private final Set<Integer> ints = ...
private final Set<String> strings = ...
public void addAll(List<Object> data) {
for (Object o : data) {
if (o instanceof Integer) {
ints.add((Integer)o);
}
if (o instanceof String) {
strings.add((String)o);
}
}
}
// Here is the method that becomes easier to write:
public void removeAll(List<Object> data) {
for (Object o : data) {
ints.remove(o);
strings.remove(o);
}
}
}
Note how removeAll method's code is simpler than the code of addAll, because remove does not care about the type of the object that you pass to it.
In your question you already explained why it can't (or shouldn't) be remove(E).
But there is also a reason why it shouldn't be remove(? super E). Imagine some piece of code where you have an object of unknown type. You still might want to try to remove that object from that list. Consider this code:
public void removeFromList(Object o, Collection<String> col) {
col.remove(o);
}
Now your argument was, that remove(? super E) is more typesafe way. But I say it doesn't have to be. Look at the Javadoc of remove(). It says:
More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this collection contains one or more such elements.
So all the preconditions the parameter has to match is that you can use == and equals() on it, which is the case with Object. This still enables you to try to remove an Integer from a Collection<String>. It just wouldn't do anything.

Why is List<Number> not a sub-type of List<Object>?

public void wahey(List<Object> list) {}
wahey(new LinkedList<Number>());
The call to the method will not type-check. I can't even cast the parameter as follows:
wahey((List<Object>) new LinkedList<Number>());
From my research, I have gathered that the reason for not allowing this is type-safety. If we were allowed to do the above, then we could have the following:
List<Double> ld;
wahey(ld);
Inside the method wahey, we could add some Strings to the input list (as the parameter maintains a List<Object> reference). Now, after the method call, ld refers to a list with a type List<Double>, but the actual list contains some String objects!
This seems different to the normal way Java works without generics. For instance:
Object o;
Double d;
String s;
o = s;
d = (Double) o;
What we are doing here is essentially the same thing, except this will pass compile-time checks and only fail at run-time. The version with Lists won't compile.
This leads me to believe this is purely a design decision with regards to the type restrictions on generics. I was hoping to get some comments on this decision?
What you are doing in the "without generics" example is a cast, which makes it clear that you are doing something type-unsafe. The equivalent with generics would be:
Object o;
List<Double> d;
String s;
o = s;
d.add((Double) o);
Which behaves the same way (compiles, but fails at runtime). The reason for not allowing the behavior you're asking about is because it would allow implicit type-unsafe actions, which are much harder to notice in code. For example:
public void Foo(List<Object> list, Object obj) {
list.add(obj);
}
This looks perfectly fine and type-safe until you call it like this:
List<Double> list_d;
String s;
Foo(list_d, s);
Which also looks type-safe, because you as the caller don't necessarily know what Foo is going to do with its parameters.
So in that case you have two seemingly type-safe bits of code, which together end up being type-unsafe. That's bad, because it's hidden and therefore hard to avoid and harder to debug.
Consider if it was...
List<Integer> nums = new ArrayList<Integer>();
List<Object> objs = nums
objs.add("Oh no!");
int x = nums.get(0); //throws ClassCastException
You would be able to add anything of the parent type to the list, which may not be what it was formerly declared as, which as the above example demonstrates, causes all sorts of problems. Thus, it is not allowed.
They aren't subtypes of each other due how generics work. What you want is to declare your function like this:
public void wahey(List<?> list) {}
Then it will accept a List of anything that extends Object. You can also do:
public void wahey(List<? extends Number> list) {}
This will let you take in Lists of something that's a subclass of Number.
I'd recommend you pick up a copy of "Java Generics and Collections" by Maurice Naftalin & Philip Wadler.
There are essentially two dimensions of abstraction here, the list abstraction and the abstraction of its contents. It's perfectly fine to vary along the list abstraction - to say, for instance, that it's a LinkedList or an ArrayList - but it's not fine to further restrict the contents, to say: This (list which holds objects) is a (linked list which holds only numbers). Because any reference that knows it as a (list which holds objects) understands, by the contract of its type, that it can hold any object.
This is quite different from what you have done in the non-generics example code, where you've said: treat this String as if it were a Double. You are instead trying to say: treat this (list which holds only numbers) as a (list which holds anything). And it doesn't, and the compiler can detect it, so it doesn't let you get away with it.
"What we are doing here is essentially
the same thing, except this will pass
compile-time checks and only fail at
run-time. The version with Lists won't
compile."
What you're observing makes perfect sense when you consider that the main purpose of Java generics is to get type incompatibilities to fail at compile time instead of run time.
From java.sun.com
Generics provides a way for you to
communicate the type of a collection
to the compiler, so that it can be
checked. Once the compiler knows the
element type of the collection, the
compiler can check that you have used
the collection consistently and can
insert the correct casts on values
being taken out of the collection.
In Java, List<S> is not a subtype of List<T> when S is a subtype of T. This rule provides type safety.
Let's say we allow a List<String> to be a subtype of List<Object>. Consider the following example:
public void foo(List<Object> objects) {
objects.add(new Integer(42));
}
List<String> strings = new ArrayList<String>();
strings.add("my string");
foo(strings); // this is not allow in java
// now strings has a string and an integer!
// what would happen if we do the following...??
String myString = strings.get(1);
So, forcing this provides type safety but it also has a drawback, it's less flexible. Consider the following example:
class MyCollection<T> {
public void addAll(Collection<T> otherCollection) {
...
}
}
Here you have a collection of T's, you want to add all items from another collection. You can't call this method with a Collection<S> for an S subtype of T. Ideally, this is ok because you are only adding elements into your collection, you are not modifying the parameter collection.
To fix this, Java provides what they call "wildcards". Wildcards are a way of providing covariance/contravariance. Now consider the following using wildcards:
class MyCollection<T> {
// Now we allow all types S that are a subtype of T
public void addAll(Collection<? extends T> otherCollection) {
...
otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T)
}
}
Now, with wildcards we allow covariance in the type T and we block operations that are not type safe (for example adding an item into the collection). This way we get flexibility and type safety.

Categories