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
Related
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.
I'm new to Java, and I'm trying to figure out one thing about generics.
If I declare a method like
public <T> List<T> toList(final T... arr) { ... }
Can I return both ArrayList and LinkedList?
Or for example, if I have declare a method like
public <T> T[] toArray(final List<T> l) { ... }
Can I pass both ArrayList and LinkedList as argument and it'll works good?
If this is right, does it works with all objects too? So, if I create a class and I extend it more times, can I use the top class as arg of method, but the pass its subclasses when I call it?
It's not about generics only. You can assign any object to a variable of its parent class.
Object o = 5; // It's valid
If you pass a LinkedList or ArrayList to the toArray()method, it doesn't matter. It will be automatically converted to List. Similarly, if you return a LinkedList from the toArray() method, it doesn't matter. It will be converted to List.
But one thing to keep in mind is if you pass a LinkedList, it will get converted to List and you will be able to use only the methods of the List interface.
List list = new LinkedList();
list.addFirst(1); // Invalid
The method signature looks like this:
public void addThemAll(Collection<? extends T> c)
Which essentially just adds every element of the collection to my LinkedList. But I keep trying to feed this method an Array or a Linked List and I always get an error. For example:
double[] myarray = new double[]{3.4, 4.5, 8.6};
mylist.addThemAll(myarray);
I'm sure this is something straightforward, but I can't find an example online that just passes an array/linked list into a method like this.
Your code has two problems:
An array is not a collection. It does not extend Collection. Therefore, you can't pass it into a method whose signature specifies a collection parameter.
You have not defined <T> (or, at least, you have not shown us where you are defining <T>). You can either define <T> in your class, or in your method signature.
To define it in your class, do it like this:
public class MyClass<T> {
// contents
}
To define <T> in your method, do it like this:
public <T> void addThemAll(Collection<? extends T> c) {
// method logic
}
For what you are doing, this would work:
List<Double> myArray = Arrays.asList(3.4, 4.5, 8.6);
mylist.addThemAll(myarray);
The reason being is that you are passing in a list (which is a collection). Currently you are passing in an Array, which is not a collection.
To pass in the array to collection:
Double[] myarray = new Double[]{3.4, 4.5, 8.6};
mylist.addThemAll(Arrays.asList(myarray));
if you don't want it as list but want it as LinkedList or etc
LinkedList<Double> linkedlist = new LinkedList(Arrays.asList(myarray));
mylist.addThemAll(linkedlist);
if you want to use set or treeset
TreeSet <Double> treeset = new TreeSet(linkedlist);
Difference between set and list is that set does not have duplicate and not ordered, and list is ordered but contains duplicates.
After you pass in to your method:
public void addThemAll(Collection<? extends T> c)
if(c instanceof LinkedList){
LinkedList a = (LinkedList) c //you can invoke methods from LinkedList
....
}
I'm putting values into the hashmap which is of the form,
Map<Long, Double> highLowValueMap=new HashMap<Long, Double>();
highLowValueMap.put(1l, 10.0);
highLowValueMap.put(2l, 20.0);
I want to create a list by using values() method of map.
List<Double> valuesToMatch=new ArrayList<>();
valuesToMatch=(List<Double>) highLowValueMap.values();
or
List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();
However, it throws an exception:
Exception in thread "main" java.lang.ClassCastException:
java.util.HashMap$Values cannot be cast to java.util.List
But it allows me to pass it in to the creation of a list:
List<Double> valuesToMatch = new ArrayList<Double>( highLowValueMap.values());
TL;DR
List<V> al = new ArrayList<V>(hashMapVar.values());
Explanation
Because HashMap#values() returns a java.util.Collection<V> and you can't cast a Collection into an ArrayList, thus you get ClassCastException.
I'd suggest using ArrayList(Collection<? extends V>) constructor. This constructor accepts an object which implements Collection<? extends V> as an argument. You won't get ClassCastException when you pass the result of HashMap.values() like this:
List<V> al = new ArrayList<V>(hashMapVar.values());
Going further into the Java API source code
HashMap#values(): Check the return type in the source, and ask yourself, can a java.util.Collection be casted into java.util.ArrayList? No
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
ArrayList(Collection): Check the argument type in the source. Can a method which argument is a super type accepts sub type? Yes
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
The answer can be found by reading the JavaDoc
The values() method returns a Collection
So
List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();
Should be
Collection<Double> valuesToMatch= highLowValueMap.values();
You can still iterate over this collection as you would a list.
http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html#values%28%29
This works:
List<Double> valuesToMatch = new ArrayList<Double>( highLowValueMap.values() );
Because ArrayList has a constructor that accepts a collection.
It's because values() returns Collection which according to source code of HashMap is of type AbstractCollection and thus cannot be cast to List.
You are able to instantiate ArrayList passing it values() result because ArrayList constructor can take Collection as its argument.
If you have already created an instance of your List subtype (e.g., ArrayList, LinkedList), you could use the addAll method.
e.g.,
valuesToMatch.addAll(myCollection)
Many list subtypes can also take the source collection in their constructor.
Have you check the API, what is returned by values() method? And what ArrayList constructor accepts?
I faced the same issue, But then I realised the values() return Collection, and not a List.
But we are able to instantiate a new ArrayList like this :
List valuesToMatch = new ArrayList(highLowValueMap.values());
Because ArrayList has a constructor that can take Collection as its argument.
Well it's because your values are really a HashSet.
You could write a code like this to iterate over the set:
List<Double> valuesToMatch=new ArrayList<>();
for(Double d : highLowValueMap.values(){
valuesToMatch.put(d);
}
Values is an inner class in HashMap class (see $ symbol in java.util.HashMap$Values).
HashMap.values() method will return Values class's object which is not implementing List interface. So is the ClassCastException.
Here is the Values inner private class in HashMap which is not implementing List interface. Even AbstractCollection is also not implementing List interface.
AbstractCollection implements Collection interface. So not able to cast to List.
private final class Values extends AbstractCollection<V> {
public Iterator<V> iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
HashMap.this.clear();
}
}
Update
Following is one of the constructor in ArrayList.
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
So hashmapObj.values() method return type is Collection. Now which class is implementing this Collection interface ? Answer is Values class which is inside the HashMap class (inner class). Returned value from hashmapObj.values() can be passed to above ArrayList constructor which is valid.
Even following is valid statements.
HashMap<String, String> map = new HashMap<String, String>();
Collection c = map.values();
But following statements are incorrect
HashMap<String, String> map = new HashMap<String, String>();
List c = map.values(); //compilation error.. return type is not List
I doubt the selected best answer, where it says:
"Because HashMap#values() returns a java.util.Collection and you can't cast a Collection into an ArrayList, thus you get ClassCastException."
It's not because Collection can't be casted to ArrayList, the real reason is that the Collection returned by HashMap.values() is backed up by the inner class HashMap.Values. And HashMap.Values is not a super class of ArrayList.
To convert the values from a Map instance to a list you could use Iterable<T>.map
val yourList: List<Any> = #Map.values.map { it }
This is part of the Java (1.6) Collection interface:
public interface Collection<E> extends java.lang.Iterable<E> {
/* ... */
boolean containsAll(java.util.Collection<?> objects);
boolean addAll(java.util.Collection<? extends E> es);
boolean removeAll(java.util.Collection<?> objects);
boolean retainAll(java.util.Collection<?> objects);
/* ... */
}
Why does addAll have <? extends E> while removeAll has <?>
I did not know, I googled. I got this explaination here: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html
Copying the part:
One element of the generifed Collections API that is often confusing at first is the signatures of containsAll(), removeAll(), and retainAll(). You might expect the signatures for remove() and removeAll() to be:
interface Collection<E> {
public boolean remove(E e); // not really
public void removeAll(Collection<? extends E> c); // not really
}
But it is in fact:
interface Collection<E> {
public boolean remove(Object o);
public void removeAll(Collection<?> c);
}
Why is this? Again, the answer lies in backward compatibility. The interface contract of x.remove(o) means "if o is contained in x, remove it; otherwise, do nothing." If x is a generic collection, o does not have to be type-compatible with the type parameter of x. If removeAll() were generified to only be callable if its argument was type-compatible (Collection<? extends E>), then certain sequences of code that were legal before generics would become illegal, like this one:
// a collection of Integers
Collection c = new HashSet();
// a collection of Objects
Collection r = new HashSet();
c.removeAll(r);
If the above fragment were generified in the obvious way (making c a Collection<Integer> and r a Collection<Object>), then the code above would not compile if the signature of removeAll() required its argument to be a Collection<? extends E>, instead of being a no-op. One of the key goals of generifying the class libraries was to not break or change the semantics of existing code, so remove(), removeAll(), retainAll(), and containsAll() had to be defined with a weaker type constraint than they might have had they been redesigned from scratch for generics.
For any collection containing elements of type E, addAll must be able to deal with input collections not just of E, but all of its subclasses as well. Hence <? extends E>. Without this, you could not add all elements of a List<Integer> to a List<Number>, which would clearly not be right.*
For removal, the limits need not be so strictly set, and there is no harm in trying to remove elements of a collection of some totally unrelated type. E.g. you can have a collection of Numbers, about which you happen to know that it only contains Integers, so passing it to removeAll on a List<Integer> should work fine, and it would be stupid for the compiler to disallow this.
Note that according to the Javadoc, removeAll may optionally throw a ClassCastException, depending on implementation.
*The reason behind this is that in Java, generics are invariant. For more details, see e.g. this thread.
<?> is less restrictive than <? extends E>.
There is nothing wrong with removing an orange from a collection of apples; there are a lot of things wrong with adding an orange to a collection of apples.
When you add item to your collection you want to be sure that they do have a certain type.
When you remove them, only those in the collection are removed. Regardless of their type.
Java implements generics through erasure. These info are only for compilation time only. I guess the java collection designers did this to retain more ascendent compatibility with pre-generics java version.
when you add an object, it needs to be a subclass (or sub-subclass, etc.) of the main type. When you remove an object, it returns it as the type oc the collection. This is a good example of polymorphism in action.
A simple example to illustrate what has been said:
public class Test {
public static void main(String[] args) {
List<String> l = new ArrayList<String>();
System.out.println(l.remove(new Object())); //false
System.out.println(l.contains(new Object())); //false
// l.add(new Object()); // does not compile
}
}
Who cares what you try to remove ?
Adding is something else; we wouldn't want to end up with something strange in our collection.
as requested; an example:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Main {
private static class A {
}
public static void main(String[] args) {
Collection<A> collection_A = new ArrayList<A>();
Collection<String> collection = new ArrayList<String>();
// no problem to try and remove things that wouldn't be there in the first place; either way, they are gone afterwards
collection.removeAll(collection_A);
// we can't allow this; you would end up with things in your collection that don't belong there
collection.addAll(collection_A);
}
}
To remove restriction is not needed, so only <?>, but while adding we have to check and then add for type safety, so addAll is with restriction <? extends E>
With addAll you want to be able to add all elements that are a subtype of the generic type. This includes adding all elements of a List<String> to a List<Object>. We use ? extends E to accept any Collection that contains the type stored in this collection or any subtype.
boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
numbers.addAll(integers);//works
boolean addAll(java.util.Collection<E> es);
numbers.addAll(integers);//does not work E != Integer
we can't use ? as that would remove any security provided by generics.
boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
List<String> strings = ...;
numbers.addAll(integers);//works
numbers.addAll(strings);//error
boolean addAll(java.util.Collection<?> es);
numbers.addAll(strings);//works - now we have strings in our Number collection
We can use ? to remove objects since trying to remove a String from List of Numbers wont affect a List<Number>.
boolean removeAll(java.util.Collection<?> objects);
List<Objects> objects = ...;
List<Integer> integers = ...;
List<Number> numbers = ...;
numbers.removeAll(objects);//works
numbers.removeAll(integers);//works
boolean removeAll(java.util.Collection<? extends E> objects);
numbers.removeAll(objects);//does not work
numbers.removeAll(integers);//works
boolean removeAll(java.util.Collection<? super E> objects);
numbers.removeAll(objects);//works
numbers.removeAll(integers);//does not work