The code i did do not work for collection. is there other way to sort an object arraylist? or how to sort it using collection.sort?
Object [] objects = BookAnalyser.array.toArray();
ArrayList<Object> uniqueword = new ArrayList<Object>();
for (Object h: BookAnalyser.WordList.findUnique(objects, objects)){
if(h != null ) {
uniqueword.add(h);
}
}
Collections.sort((uniqueword)); //Error: The method sort(List<T>) in the type Collections is not applicable for the arguments (ArrayList<Object>)
for(Object j : uniqueword) {
System.out.print(j+ " ");
}
It shows The method sort(List) in the type Collections is not applicable for the arguments (ArrayList). Normally it would work just fine.
You are trying to sort a List<T> where T is Object.
The definition of Collections.sort is
static <T extends Comparable<? super T>> void sort(List<T> list)
which means the type parameter must implement Comparable<? super T>, which Object does not.
Two solutions:
Make uniqueword a list of some type implementing Comparable, such as String
Provide your own custom Comparator<Object>, but you'll have to downcast to something that can be compared, so the first option (List<String> for example) is much preferred.
Related
I've read a few topics which cover certain questions about generics, such as their relationship with raw types. But I'd like an additional explanation on a certain line found in the Java SE tutorial on unbound generics .
According to a sentence :
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>.
If I understand well this sentence; the difference between List<?> and List<Object>, is that we can use the type argument List<String> or List<Integer> by implementing the former. While if we implement the later, we can only use the type argument List<Object>. As if List<?> is an upper bound to Object namely List<? extends Object>.
But then the following sentence confuses me, in the sense that according to what I previously understood, List<Object> should only contain instances of the class Object and not something else.
It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>.
There are two separate issues here. A List<Object> can in fact take any object as you say. A List<Number> can take at least Number objects, or of course any subclasses, like Integer.
However a method like this:
public void print(List<Number> list);
will actually only take a List which is exactly List<Number>. It will not take any list which is declared List<Integer>.
So the difference is List<?> will take any List with whatever declaration, but List<Object> will only take something that was declared as List<Object>, nothing else.
The last quote simply states, that List<?> is a list for which you literally don't know what type its items are. Because of that, you can not add anything to it other than null.
The sentence that is confusing you is trying to warn you that, while List<?> is the super-type of all generic lists, you cannot add anything to a List<?> collection.
Suppose you tried the following code:
private static void addObjectToList1(final List<?> aList, final Object o ) {
aList.add(o);
}
private static void addObjectToList2(final List<Object> aList, final Object o ) {
aList.add(o);
}
private static <T> void addObjectToList3(final List<T> aList, final T o ) {
aList.add(o);
}
public static void main(String[] args) {
List<String> testList = new ArrayList<String>();
String s = "Add me!";
addObjectToList1(testList, s);
addObjectToList2(testList, s);
addObjectToList3(testList, s);
}
addObjectToList1 doesn't compile, because you cannot add anything except null to a List<?>. (That's what the sentence is trying to tell you.)
addObjectToList2 compiles, but the call to it in main() doesn't compile, because List<Object> is not a super type of List<String>.
addObjectToList3 both compiles and the call works. This is the way to add elements to a generic list.
There are a number of question on Stack Overflow about sorting Generics; however, I am interested in sorting Generics in the simplest way: nothing nested. The code I have below is an attempt to sort a generic set - or, list - of elements.
List<E> l = new LinkedList<>(arbSet);
Collections.sort(l);
arbSet is just a set of elements: Set<E> arbSet.
Clearly, this is problematic - it shouldn't work. To make sure I know this, Eclipse gives me the following for my attempt to call .sort:
Bound mismatch: The generic method sort(List < T >) of type Collections is not applicable for the arguments (List < E >). The inferred type E is not a valid substitute for the bounded parameter < T extends Comparable < ? super T >>
So, I do a bit of documentation consultation, looking at sort's specifications.
As a result, I attempt to ensure that sort knows E extends Comparable:
The first line now looking like:
List<E extends Comparable<? super E>> l = new LinkedSet<>(arbSet);
Now, Eclipse states :
Syntax error on token "extends", , expected
What am I missing? I feel like this is a very basic example and that I am just missing something "palm-to-face" esque. Just to simplify it even further, all arbSet elements are elements which implement the Comparable interface.
You can use Collections.sort() only if you provide a custom Comparator or if the elements you are trying to sort implement the Comparable interface. So it depends on what elements are stored in arbSet.
For example, if you wanted to create a method that accepts a set, and returns a list with the set elements sorted, you would do something like this:
static <E extends Comparable<E>> List<E> sortedListFrom(Set<E> set) {
List<E> l = new LinkedList<>(set);
Collections.sort(l);
return l;
}
Edit:
If you want to do this inside a constructor you have two options:
Declare the type E just before the constructor. Of course, this won't do much, since list is lost after the constructor finishes.
class Test {
<E extends Comparable<E>> Test(Set<E> arbSet) {
List<E> list = new LinkedList<>(arbSet);
Collections.sort(list);
System.out.println(list);
}
}
Declare the type E in the class, so you can store the result in a attribute.
class Test<E extends Comparable<E>> {
List<E> list;
Test(Set<E> arbSet) {
this.list = new ArrayList<>(arbSet);
Collections.sort(this.list);
System.out.println(this.list);
}
}
If I want to sort the Collection below by a property called Order on the CSVInputHandler class, how do I do that? I tried the one a the very bottom with no luck. The error says The method sort(List<T>, Comparator<? super T>) in the type Collections is not applicable for the arguments (Collection<CSVInputHandler>, Comparator<CSVInputHandler>).
Object
Collection<CSVInputHandler> csvInputHandlers = new ArrayList<>(csvInputHandlerMap.values());
Tried
Comparator<CSVInputHandler> comparator = new Comparator<CSVInputHandler>() {
public int compare(CSVInputHandler c1, CSVInputHandler c2) {
return c1.Order < c2.Order;
}
};
Collections.sort(csvInputHandlers, comparator);
In order to sort a Collection (by using Collections.sort) you must explicitly convert it into a List
List<CSVInputHandler> myList = new ArrayList<>(csvInputHandlers);
Collections.sort(myList, comparator);
Remove .toArray() as that sort method accept only List types not Array
Collections.sort(csvInputHandlers, comparator);
Def
public static <T> void sort(List<T> list, Comparator<? super T> c) {
The Collections#sort method acts on Collections so the first method argument must be a Collection (i.e. any concrete subtype such as List, Set) while you are trying to as an array element as a first argument. It should be
Collections.sort(csvInputHandlers, comparator)
Collection :
The root interface in the collection hierarchy. A collection represents a group of objects, known as its elements. Some collections allow duplicate elements and others do not. Some are ordered and others unordered
source http://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
There is a method :
public static <T> void addandDisp(Collection<T> cs, T t)
which is being called in the following way :
List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2,new Object());
This gives a compile time error. On the other hand, if we had only one parameter, then the call is successful. Why is that ?
Moreover, this is successful :
List<? super String> ls1 = new LinkedList<String>();
addandDisp(ls1,new String());
while this is not :
List<? super String> ls1 = new LinkedList<Object>();
addandDisp(ls1,new Object());
What is the underlying logic ?
I would assume that addandDisp means add and display.
When you have a collection, defined as:
List<? extends Object> ls2 = new LinkedList<Number>();
This means that the compiler will allow you to assign the colletion to all the possible unknown subtypes of Object. Since you have the operation add, the compiler denies to give you green light, because it doesn't know if the provided object's type meets the restriction to be of the unknown subtype of Object. This is called covariance.
Similary, when you have a definition like this:
List<? super String> ls1 = new LinkedList<String>();
The compiler allows you to assing ls1 to:
LinkedList<String>(); //you can add Strings to the list
LinkedList<Object>(); //you can add Strings and Objects to the list
In this case, the compiler will be completely aware if the object you're trying to pass meets the condition to be subtype of the generic type of the collection. This is called contravariance.
More info:
What is PECS?
Here is another approach, but others gave a quite detailed response.
The first example:
List<? extends Object> ls0 = new LinkedList<Number>();
addandDisp(ls0, new Object());
Here ls0 may be of any type that is a subclass of Object, like a Number as your example shows.
Now what if this could work? It would mean that if you can put an Object into any of the collections.
Imagine I want to iterate your previous list of Number objects:
for (Number n : numbers) {
...
}
If I could put an Object here, then Plaff! I would get a class cast exception immediately.
The second example
List<? super String> ls1 = ...;
addandDisp(ls1,new String());
Let's play a bit with the object hierarchy: String is a subclass of CharSequence which is a subclass of Object.
You get ls1 here which is an unknown supertype of String (e.g., a CharSequence). Is it all right to put a String into a list of character sequences? Yup, it's okay, since they share the same interface for sure! You can handle them through it in the same way.
The third example
List<? super String> ls1 = ...;
addandDisp(ls1,new Object());
Let's suppose the previous situation: you assign ls1 a list of CharSequences. Can you add an object to a List<CharSequence>? Nope, for the same reason as the first example fails.
Hope that helps clarifying your issues a bit :-)
On the other hand, if we had only one parameter, then the call is successful. Why is that ?
Your method has a single type parameter. When you invoke a method, you either provide a type argument explicitly or have one be inferred implicitly.
When you invoke it like
addandDisp(ls2, new Object());
the compiler needs to extract a type to bind to T from both method arguments, since both method parameters rely on the method's type parameter, T.
The issue here is that ? extends Object and Object do not produce a single type that can be bound to T safely. Imagine you had
public static <T> void addandDisp(Collection<T> cs, T t) {
cs.add(t);
}
...
List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2, new Object());
This add should not be allowed since an Object should not be used where a Number would have been expected. Type safety would break.
If you have a single parameter
public static <T> void addandDisp(Collection<T> cs) {
Then the compiler uses the single argument to infer the type argument. There is then no ambiguity about what to use.
1 example: Object is not ? extends Object (for example, Number is ? extends Object, but Object is not Number). Thus, it is not type safe.
2 example: String is ? super String. It is type safe.
3 example: Object is not ? super String. Not safe again.
Supposedy i have the following:
class x {
public static void main(String [] args) {
List <?> a = new LinkedList<Object>();
List <? extends Object> b = new LinkedList<Object>();
List <? super Object> c = new LinkedList<Object>();
abc(a, "Hello"); // (1) Error
abc(b, "Hello"); // (2) Error
abc(c, "Hello"); // (3) ok
def(b); // (4) ok
// Showing inference at work
Integer[] a = {10, 20, 30}; // (5)
T is inferred to be ? extends Object
Method signature: ppp(? extends Object, ? extends Object[])
Method call signature: ppp(String, Integer[]);
ppp("Hello", a); // ok
}
static <T> void abc(List<T> a, T b) {}
static <T> void def(List<T> a) {}
static <T> void ppp(T t1, T[] t2){}
}
To begin with, look at clause 5 showing inference at work. Now clause 5 section is a working section.
If that is what it is, then why does clause (1) & (2) have errors?
From my view, all these 3 methods calling have the same inference generated since no actual type parameters is used on the abc method call.
method parameter <T> abc (List <T> a, T b>)
inferred <Object> abc (List <Object>, Object) // (4)
Please bear in mind, method abc() and def() is my method. Compiler doesn't know what i want to do with the List in this method. I might just print the list size or might not even do anything at all as shown above. So there is no get or set involved here.
CONTINUATION -->
This is getting very confusing for me.
class y {
public static void main(String [] args) {
List <Integer> a = new LinkedList<Integer>();
List <Object> b = new LinkedList<Object>();
ppp("Hello", new Integer(1)); // (20) ok
qqq("Hello", a); // (21) error
qqq("Hello", b); // (22) ok
}
static <T> void ppp(T t1, T t2) {}
static <T> void qqq(T t1, List <T> t2) {}
}
Note that clause 21 is the same as clause 20 except 2nd parameter is being made to be a List instead of Integer.
Clause 20 is ok cos' T is inferred to be Object.
Clause 22 is ok. Same reason as clause 20.
Clause 21 failed? T could also be inferred to be Object too - would work too?
The hard thing about the wildcard is to realize ? extends Foo does not mean "anything that extends Foo", but instead it means "some specific type that extends Foo". And since you are outside that definition, you have no way to know which specific sub-type of Foo it is.
Update:
As I said, it's complicated. Here are some comments on your code.
// a list of some specific type, and you don't know what type that is.
// it's a sub-type ob Object, yes, which means that you can do
// Object foo = a.get(0); , but the compiler has no way of knowing
// whether it's a String so you can't pass in a String
List <?> a = new LinkedList<Object>();
// same here. '?' and '? extends Object' are equivalent
List <? extends Object> b = new LinkedList<Object>();
// this is a list of Objects and superclasses thereof.
// since there are no superclasses of Object, this is equivalent to
// List<Object>. And through inheritance, a String is an Object, so
// you can pass it in.
List <? super Object> c = new LinkedList<Object>();
Update 2:
The problem here is that you are dealing with fixed, but unresolveable variables.
// you can pass in a List<String> and a String,
// but if you pass in a List<?>, the compiler has no idea what
// '?' is and just can't substitute 'String'.
// 'T' doesn't help you here, because 'T' can't match both
// '?' and 'String'.
static <T> void abc(List<T> a, T b) {}
// this works because 'T' substitutes '?' and doesn't have to worry
// about a 2nd parameter
static <T> void def(List<T> a) {}
Read this question, it might shed some light on the problem:
What is PECS (Producer Extends Consumer Super)?
You've set up a bit of a straw man by creating a LinkedList<Object> in each case. That can make it difficult to see the problem. What you have to remember is that when the compiler gets to those method invocations, it doesn't know that you created a LinkedList<Object>. It could be a LinkedList<Integer>, for example.
So let's look at your code with more interesting initializations:
List<Integer> integers = new LinkedList<Integer>();
List <?> a = integers;
List <? extends Object> b = integers;
List <? super Object> c = new LinkedList<Object>();
//INVALID. T maps to a type that could be Object OR anything else. "Hello"
//would only be type-assignable to T if T represented String, Object, CharSequence,
//Serializable, or Comparable
abc(a, "Hello");
//INVALID. T maps to a type that could be Object OR anything else. "Hello"
//would only be type-assignable to T if T represented String, Object, CharSequence,
//Serializable, or Comparable
abc(b, "Hello");
//VALID. T maps to an unknown super type of Object (which can only be Object itself)
//since String is already type-assignable to Object, it is of course guaranteed to be
//type-assignable to any of Object's super types.
abc(c, "Hello");
Integer i1 = integers.get(0);
Integer i2 = integers.get(1);
It doesn't take much to see that if the implementation of abc was this:
//a perfectly valid implementation
static <T> void abc(List<T> a, T b) {
a.add(b);
}
That you would get a ClassCastException when initializing i1.
From my view, all these 3 methods calling has the following inference generated since no actual type parameters is used on the abc static method call.
method parameter <T> abc (List <T> a, T b>)
inferred <Object> abc (List <Object>, Object) // (4)
This is categorically wrong. It is not inferred that T is Object in any of your examples, not even in the case of ? super Object. T is resolved to the capture of a, and unless you can assign a String to that capture (as is the case when it's ? super Object) you will have a type error.
Edit #1
Regarding your update (I've replaced your generic array with a List<T> since generic arrays needlessly cloud the issue):
// Showing inference at work
List<Integer> a = Arrays.asList(10, 20, 30); // (5)
T is inferred to be ? extends Object
Method signature: ppp(? extends Object, List<? extends Object>)
Method call signature: ppp(String, List<Integer>);
ppp("Hello", a); // ok
This is not correct. The crucial mistake you're making is here:
Method signature: ppp(? extends Object, List<? extends Object>)
This is not at all what the capture engine does or should translate your invocation into. It resolves T as <? extends Object> but as one specific capture of <? extends Object>. Let's call it capture-1-of<? extends Object>. Thus your method must be like this:
Method signature: ppp(capture-1-of<? extends Object>, List<capture-1-of<? extends Object>>)
This means that there is a binding between the two parameters...they must resolve to the same capture. In general it is very difficult to tell the compiler that two things are the same capture. In fact, even this is not a valid invocation of ppp (even though they are clearly the same capture):
List<? extends Integer> myList;
ppp(myList.get(0), myList);
One way we could invoke ppp is through a generic intermediary:
public static <T> void pppCaller(List<T> items) {
ppp(items.get(0), items);
}
pppCaller(myList);
The only sure-fire way you could invoke ppp with a wildcarded list would be to invoke it like this:
List<? extends Integer> myList = new ArrayList<Integer>();
ppp(null, myList);
That's because the null is the only thing that you can assign to anything. On the other hand, if you had this method:
private static <T> void qqq(T item1, T item2) {}
You could indeed invoke it like this:
List<? extends Integer> myList;
qqq(myList.get(0), myList.get(1));
Because in this case, the inference can generalize T to Object. Since List<? extends Integer> is not covariant with List<Object>, it cannot do the same for ppp().
However, what most people do to get around this is to relax their method signature. Instead, declare ppp as the following:
public static <T> ppp(T item, List<? super T> items) {
}
This follows the guidelines that Sean put in his post of "PECS"
If (your method) produces, use extends, if it consumes, use super.
Edit #2
Regarding your latest edit:
public static void main(String [] args) {
List <Integer> a = new LinkedList<Integer>();
qqq("Hello", a); // (21) error
}
static <T> void qqq(T t1, List <T> t2) {}
Object is not a valid inference for T. I think this is something fundamental you're missing, so I'll say it clear:
A List<Integer> is NOT type-assignable to List<Object>
Not at all. If it were, you could do something like this which obviously violates type safety:
List<Integer> myInts = new ArrayList<Integer>();
List<Object> myObjects = myInts; //doesn't compile!
myObjects.add("someString");
Integer firstInt = myInts.get(0); //ClassCastException!
So T cannot be inferred as Object, since it would require assigning a List<Integer> to a variable of type List<Object>.
A wildcard would then needed to induce subtype covariance
I'd rather say "try to simulate" since even after using wild-cards you can't get the same functionality you get for arrays.
Then the question is why clause (3) works and not clause(2) or (1)?
Consider the first declaration:
List <?> a = new LinkedList<Object>();
This declaration effectively says, I really don't know (or care) what kind of element the collection a contains. This effectively shuts you off from "mutating" the collection since you might end up adding elements of type which are not really compatible with a. You can have List<?> a = new ArrayList<String>() but you still won't be able to put anything in it. Basically, in case an add is allowed, the compiler can't guarantee the type safety of the collection.
List <? extends Object> b = new LinkedList<Object>();
Here you say b is a collection which contains elements which extend an Object. What kind of element, you don't know. This again as per the previous discussion doesn't allow you to add anything since you could end up compromising type safety.
List <? super Object> c = new LinkedList<Object>();
Here you say, c is a collection which contains elements of type Object and it's super-classes or in other words, at least an Object. Since each reference type in Java is assignment compatible with Object, it works in the third case.
Integer[] is a subtype of Object[], however List<Integer> is not a subtype of List<Object>. This is quite confusing; arrays are more primitive and should be avoided.
If a method parameter type is T[], it accepts all S[] where S is a subtype of T.
To do this with List, the type should be List<? extends T>. It accepts all List<S> where S is a subtype of T.
List<?> a means that a holds a specific type, which is unknown. Consider this more complete example:
List<Float> floats = new ArrayList<Float>();
List<?> a = floats; /* Alias "floats" as "a" */
abc(a, "Hello"); /* This won't compile... */
float f = floats.get(0); /* .. if it did, you'd get a ClassCastException */
static <T> abc(List<T> a, T b) {
a.add(b); /* Absolutely no problem here. */
}
List<? extends Object> means essentially the same thing as List<?>, and would cause the same error.
List<? super Object> means that the list holds a specific, but unknown super-type of Object, and the parameterized method can accept any object that is-a Object for the second parameter. While the method invocation is type-safe, attempting to assign an unsafe value to c will cause an error:
List<Number> numbers = new ArrayList<Number>();
List<? super Object> a = numbers; /* This won't compile... */
abc(a, "Hello");
Number n = numbers.get(0); /* ...if it did, you'd get a ClassCastException */