I have added some Integers to an ArrayList of object type, and want it to be sorted. My code looks like:
List<Object> list = new ArrayList<Object>();
list.add(24);
list.add(2);
list.add(4);
Collections.sort(list); // getting error here
System.out.println("Sorted list ");
for (Object e : list) {
System.out.println(e);
}
I got the following compile-time error:
error : should implement java.lang.Compareble <? super java.lang.Object>
How should I resolve this issue?
Object class doesn't implement Comparable interface. If you're sure you're adding Integer you can use code as below and then perform sorting.
List<Integer> list = new ArrayList<Integer>();
From sort() method docs
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
The error message that your IDE generating is
The inferred type Object is not a valid substitute for the bounded parameter >
Which means that the Objects being put in that List must implement Comparable interface to accept in sort() method.
Object class not implementing comparable interface, hence the error which you are seeing.
Using Object of type in Generic is not advisable and use specific type. Since you are adding all integers to the list just change your declaration to
List<Object> intList = new ArrayList<Object>();
If any other object of your own type, just implement comparable interface in that class or pass a custom comparator as a second parameter to sort.
Since you have declared your list to have the type List<Object>, you are able to store anything into it, be it comparable or not.
The generic method Collections.sort(List) has a type signature which requires that your list has an element type which implement the Comparable interface, which ensures that all elements can be compared to each other, and it tells the sort method how to compare these elements, as said interface contains the method which can be called to compared two elements. In other words, it does not accept a List that could contain anything.
So is your case, you should change the declaration to
List<Integer> list = new ArrayList<>();
as you are only adding Integer objects. Integer is a type which implements Comparable as integer values have a natural order.
Note that you can simplify your code:
List<Integer> list = Arrays.asList(24, 2, 4);
Collections.sort(list);
System.out.println("Sorted list "+list);
The list returned by Arrays.asList does not support changing its size, but reordering the elements is supported, hence you can sort that list.
As a side note, in the rare case, you have a List<Object> whose type you can’t change, but you know for sure that it contains only elements being naturally comparable to each other, you can circumvent the type constraint of Collection.sort:
Collections.sort(list, null);
The method Collections.sort(List, Comparator) supports arbitrary element types as the second parameter tells how to compare them. As a special case, a comparator of null mandates natural order, but null passes every type check. But, of course, using this trick will backfire when the assumption about the elements is wrong.
Generally, you should ensure that the element type as declared at compile-type is appropriate for the desired operation. Here, using List<Integer> when the list is supposed to contain Integers is the right way.
Instead of doing Collections.sort(list), you can loop through the array and sort the objects from least to greatest.
you can do it like this:
for(int i = 0; i < intList.size(); i++) {
// if an integer is larger than any of the ones after it in the array, switch them.
}
the Object class does not implement the Comperable interface, hence it gives you this error. You should rather define it as List<Integer>, or define a custom comperator class and pass it as an aditional Argument.
public class Comp<T> implements Comparator<T>{
#Override
public int compare(T o1, T o2) {
if(o1 instanceof Integer && o2 instanceof Integer) {
int a = (Integer) o1;
int b = (Integer) o2;
return a-b;
}
return 0;
}
}
// Call it as
Collections.sort(list, new Comp<Object>());
But you may run in several Problems while using a List of Objects and a custom Comperator, since you could add everyting to this list.
Related
i want to get the data from list in asc order..
List<Region> region = (List<Region>) model.get("region");
if i am using Collection.sort(region);
then showing this,
The method sort(List) in the type Collections is not applicable for the arguments (List)
You need to define the class Region as Comparable or you need to pass an additional parameter of type Comparator to the sort method.
Without a Comparator the signature is
public static <T extends Comparable<? super T>> void sort(List<T> list)[1]
and the javadoc explicitly said that the class must implements Comparable:
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
in this case you need to modify your code as follow:
public class Region implements Comparable {
public int compareTo(Region o) {
// Add the logic to compare regions here.
}
...
}
The second version with a Comparator has the following signature:
public static <T> void sort(List<T> list, Comparator<? super T> c)
and all the elements must be comparable using the passed Comparator:
Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
In this case you need to change your code directly calling the sort method as follow:
Collections.sort(regionList, (Region r1, Region r2)-> {
// Add compare logic here
});
Note: there is an additional little mistake in your code the class to use is Collections (with an s) and not the interface Collection. I also changed the name of the list from region to regionList (eventually name it regions) because it is not only a single element but it is a list.
Custom comparator in a line for your code,
List<Region> region = (List<Region>) model.get("region");
Collections.sort(region, new Comparator<Region>() {
#Override
public int compare(Region a1, Region a2) {
return a1.getType().compareToIgnoreCase(a2.getType()); //You can alter this condition based on your condition to compare
}
});
You can leave the sorting to the database query.
As it seems the values should be unique, you could also have as model a SortedSet, implementing class: TreeSet.
i done with it...
Collections.sort(region, new Comparator<Region>() {
public int compare(Region obj1, Region obj2) {
return obj1.getStrRegion().compareTo(obj2.getStrRegion());
}
});
I inserted these two ArraysList into this List:
ArrayList<String> category = new ArrayList<>();
ArrayList<Integer> number = new ArrayList<>();
List list = new ArrayList<>();
category.add("cat");
category.add("dog");
category.add("fish");
category.add("Hamster");
number.add(1);
number.add(2);
number.add(3);
number.add(4);
list.add(category);
list.add(number);
Now how do I get the size of each array in this list?
Try like this
int sizeOfCategory = category.size();
int sizeOfNumber = number.size();
OR
for(Object li : list) {
System.out.println(((List) li).size());
}
Cast the result object of get method from the list with ArrayList.
for(int i=0; i<list.size(); i++) {
System.out.println(((ArrayList)list.get(i)).size());
}
Check object instanceOf, if it is type of ArrayList which you added, then down-cast it to ArrayList and get size.
list.add(category);
list.add(number);
for (Object o : list) {
if (o instanceof ArrayList) {
System.out.println(((ArrayList) o).size());
} else {
// unknown type
}
}
If you want you can get List item type too.
System.out.println("Object is type of " + o.getClass());
The problem is that you are using the raw typ of List. You would get it on your own, if you had declared list using a generic type T for List<T> which provides a size() method. Using the raw type the interface List will return elements of type Object - hence there is no size() method.
As list contains two instances of ArrayList there are some candidates for T available. For example:
ArrayList<?>
List<?>
Collection<?>
It depends on what you need to do with the inner lists (category, number). If you need only the size of them then Collectiion<?> will be sufficient.
System.out.println(list.get(0).size()); // 4
System.out.println(list.get(1).size()); // 4
Since the inner lists are using Integer and String as their types, there is no much they have in common in order to replace the wildcard <?>. String and Integer are both implementing Comparable but are only comparable to instance of their own type. Thus declaring List<Collection<? extends Comparable<?>>> list will not give any additional value. Hence having list which contains both inner lists of different types without a useful common type limits the usability of list to cases where you don't need the concrete type of the elements of the inner lists.
Further reading: What is a raw type and why shouldn't we use it?
I have an ArrayList of Person objects. A Person has name, age and height. My goal is to sort this ArrayList<Person>. I have implemented Comparable<Person> and have defined compareTo() but when I try to sort it, it give me this error:
The method sort(Comparator) in the type ArrayList is not applicable for the argument ()"
The way I understand is that if you implement Comparable and then define compareTo everything else is magically done for you.
Can some one explain how to this works and why I am getting this error?
My guess is that your code looks like this:
ArrayList<Person> people = ...;
people.sort();
Look at the JavaDoc for ArrayList. Do you see a method public void sort() (with no parameters)? No - there is no such method.
That is the meaning of the error: The method sort(Comparator) in the type ArrayList is not applicable for the argument () -- There is a method sort(Comparator), but you have not supplied parameters that match it.
Assuming Person implements Comparable (and therefore has a compareTo() method), you can use Collections.sort(), which sorts arbitrary List<Comparable>
Collections.sort(people);
This is because Collections has a static method:
static <T extends Comparable<? super T>> void sort(List<T> list);
(it also has a sort(List<T> list, Comparator<T> comparator))
... or you can pass a comparator to List.sort(), which is quite easy with Java 8 lambdas:
people.sort((a,b) -> a.compareTo(b));
(Or, if you prefer the old style):
people.sort(new Comparator<String>() {
#Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
(Actually as of Java 8, this comparator is provided by the standard library, as Comparator.naturalOrder())
The point of comparators is that you can sort according to different criteria. For example:
people.sort((a,b) -> a.lastName().compareTo(b.lastName()));
people.sort((a,b) -> a.lastName().compareToIgnoreCase(b.lastName()));
people.sort((a,b) -> Integer.compare(a.age(),b.age()));
// etc.
... or using methods in Comparator:
people.sort(Comparator.comparing(Person::lastName));
people.sort(Comparator.comparing(Person::lastName)
.thenComparing(Person::firstName));
Either you use a structure which uses the Comparable interface to order its elements when you add a new element inside it :
TreeSet<Person> persons = new TreeSet<>();
Person personOne = ...
Person personTwo = ...
persons.add(personOne);
persons.add(personTwo);
Either you use a List and the Collections.sort(List<T> list) method which takes as argument the list you want to sort (there is an overload of this method but it is not relevant in your case):
List<Person> persons = new ArrayList<>();
Person personOne = ...
Person personTwo = ...
persons.add(personOne);
persons.add(personTwo);
Collections.sort(persons);
With the TreeSet, the elements are sorted as soon as added and with the List, the elements are not sorted when you add them. Only, the call to the Collections.sort() method sorts the list.
Today I was asked this interview question:
If I have a Person class with name, age and salary fields, and I put 100 new instances of this Person in an ArrayList, and then do Collections.sort(list), then on what parameter will the list be sorted?
I understand that I need to have the Person class implement Comparable and then override compareTo, but if I don't do that, what will happen?
It wouldn't compile: the 1-argument version of Collections.sort expects a list of Comparables. Specifically, a List<T> where T implements Comparable<? super T>.
Yes you can sort a collection without making the elements implement the Comparable Interface, you do this
List<YourType> theList = new ArrayList<>();
Collections.sort(theList, new Comparator<YourType>(){
public int compare(YourType obj1, YourType obj2) {
// this method should return < 0, 0 or > 0
// whether obj1 is less than, equal to
// or greather than obj2
return 0;
}
});
/edit,
if you use Collections.sort(List) then it will compile only if the list is generic and it's elements implements Comparable. And if so, then the implementation of the compareTo(Obj) on each element is what will determine the ordering in the list after the sort(List) method is called
as the Collections API states:
public static <T extends Comparable<? super T>> void sort(List<T> list)
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
If the Person class does not implement Comparable<Person>, then (as the compiler will inform you):
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<Person>). The inferred type Person is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>.
(If you happened to have a Comparator<Person> lying around, Collections.sort(myList, myComparator) would sort it by the ordering specified by the comparator.)
So there's Arrays.asList(T... a) but this works on varargs.
What if I already have the array in a T[] a? Is there a convenience method to create a List<T> out of this, or do I have to do it manually as:
static public <T> List<T> arrayAsList(T[] a)
{
List<T> result = new ArrayList<T>(a.length);
for (T t : a)
result.add(t);
return result;
}
Just because it works with varargs doesn't mean you can't call it normally:
String[] x = { "a", "b", "c" };
List<String> list = Arrays.asList(x);
The only tricky bit is if T is Object, where you should use a cast to tell the compiler whether it should wrap the argument in an array or not:
Object[] x = ...;
List<Object> list = Arrays.asList((Object[]) x);
or
Object[] x = ...;
List<Object[]> list = Arrays.asList((Object) x);
As you probably already know, there is a Static class called java.util.Collections which has a number of useful methods for dealing wit arrays such as searching and sorting.
As for your question, the Collection interface specifies methods to add, remove and toArray, amongst others. For one reason or another, the API's authors decided that the add and addAll method will be the only input functions provided to the user.
One explanation for why Java Lists cannot add arrays of objects is that Lists use an iterator and iterators are more strict in their scrolling (i.e. going to the next value) than Arrays which do not have to have all their index values i=(1, 2, 5, 9, 22, ...).
Also, Arrays are not type safe; that is, they cannot guarantee that all their elements conform to a specific super-class or interface, whereas generics (of which List is a member) can guarantee type safety. Hence, the list has the chance to validate each item using the add method.
I think that you can rest assure that your method of adding an array to a list is one of the most (if not most) efficient way of achieving this effect in Java.