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 }
Related
Here is my method. I want to return a collection of strings from a Java method. I would like for the calling code to decide whether it wants to implement this collection as a Vector or a LinkedList or an ArrayList or something else that implements the List interface.
public List<String> findAvailableLanguages() {
Iterator<Map.Entry<String, String>> it = this.iterator();
List<String> list = new ArrayList<String>();
while (it.hasNext()) {
Map.Entry<String, String> n = it.next();
list.add(n.getKey());
}
...
However, I must instantiate a concrete class object inside of the method in order to build the collection. What do I now return that will be compatible with any class that implements List?
Is this possible?
It's more effective for the callers if you allow a List to be passed in the filling process instead of initiating your own. It will also make for code that's easily unit-testable, as this does the pattern known as Dependency Injection.
public List<String> populateWithAvailableLanguages(List<String> list) {
Iterator<Map.Entry<String, String>> it = this.iterator();
// List<String> list = new ArrayList<String>();
while (it.hasNext()) {
Map.Entry<String, String> n = it.next();
list.add(n.getKey());
}
}
Now the implementation of the List can be specified by the caller:
List<String> availableLanguages = new ArrayList<>();
Localizer.populateWithAvailableLanguages(availableLanguages);
In short, returning an ArrayList object type that can be cast into any other object type that implements List is not possible. The elements can be traversed and added to another object type but the collection type itself cannot be cast.
I'll explain why. When you say,
List<String> list = new ArrayList<String>();
the reference type of 'list' is List and the object type is ArrayList. The 'list' object that you now have gives you access to all the methods of the List interface but not to the other methods that ArrayList has although the list object can see them (kind of like a narrowing conversion). You can cast this list object back to an ArrayList object and that would work because the list instance anyway could see the methods that ArrayList had and hence casting this back will work (kind of like a widening conversion back to the original width).
But if you were to cast it to one of the other classes implementing the List interface like LinkedList or Vector or Stack, what will happen? The list instance does not know how the other methods present in LinkedList, Vector or Stack are implemented (as they are not in ArrayList). So it's kind of like a conversion where you do not know what needs to be done. So it will throw back a compiler error.
Extending this, you can see, if you had:
List<String> list = new LinkedList<String>();
now, casting the list back to a LinkedList will work but not back to an ArrayList.
Your method signature should be as below
Public Collection(? super List) findAvailableLanguages(){}
I have three Maps:
Map<Integer,ArrayList<ItemType1>> map1;
Map<Integer,ArrayList<ItemType2>> map2;
Map<Integer,ArrayList<ItemType3>> map3;
I frequently want to look up a key into a map and add an item to it's ArrayList value. I want to make a method that will take as a parameter a map Map<Integer,ArrayList<T>> (with an ArrayList value of a generic type T), a key to add to, and an item of type T to add to that map.
In theory something like this (I know this is not working Java code):
private void addToListInMap(Map<Integer,ArrayList<T>> map,Integer keyValue, T itemToAdd){
ArrayList<T> listOfItems= map.get(keyValue);
if(listOfItems == null){
listOfItems= new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
How can I achieve something like this using generics?
This isn't too terribly difficult: provide the generic type as a type argument to your method.
All your code is missing is the type parameter to it. Then, it should "just work".
private <T> void addToListInMap(Map<Integer, ArrayList<T>> map,
Integer keyValue, T itemToAdd) {
ArrayList<T> listOfItems = map.get(keyValue);
if (listOfItems == null) {
listOfItems = new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
You need to type the method, so code in the method has access to it (to create the new list).
private static <T> void addToListInMap(Map<Integer,ArrayList<T>> map, Integer keyValue, T itemToAdd {
ArrayList<T> listOfItems = map.get(keyValue);
if (listOfItems == null) {
listOfItems = new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
I made the method static too, since it doesn't need access to any fields to work.
You should also consider making the type of the value List<T> instead of ArrayList<T> - see Liskov substitution principle
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 would like to use simpleJdbcInsert class and executeBatch method
public int[] executeBatch(Map<String,Object>[] batch)
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/core/simple/SimpleJdbcInsert.html
So I need to pass an array of Map<String,Object> as parameter. How to create such an array?
What I tried is
Map<String, Object>[] myArray = new HashMap<String, Object>[10]
It is error: Cannot create generic array of Map<String, Object>
A List<Map<String, Object>> would be easier, but I guess I need an array. So how to create an array of Map<String, Object> ?
Thanks
Because of how generics in Java work, you cannot directly create an array of a generic type (such as Map<String, Object>[]). Instead, you create an array of the raw type (Map[]) and cast it to Map<String, Object>[]. This will cause an unavoidable (but suppressible) compiler warning.
This should work for what you need:
Map<String, Object>[] myArray = (Map<String, Object>[]) new Map[10];
You may want to annotate the method this occurs in with #SuppressWarnings("unchecked"), to prevent the warning from being shown.
You can create generic array of map.
Create a list of maps.
List<Map<String, ?>> myData = new ArrayList<Map<String, ?>>();
Initialize array.
Map<String,?>[] myDataArray = new HashMap[myData.size()];
Populate data in array from list.
myDataArray = myData.toArray(myDataArray);
I have had some difficulty with this, but I have figured out a few things that I will share as simply as possible.
My experience with generics is limited to collections, so I use them in the class definitions, such as:
public class CircularArray<E> {
which contains the data member:
private E[] data;
But you can't make and array of type generic, so it has the method:
#SuppressWarnings("unchecked")
private E[] newArray(int size)
{
return (E[]) new Object[size]; //Create an array of Objects then cast it as E[]
}
In the constructor:
data = newArray(INITIAL_CAPACITY); //Done for reusability
This works for generic generics, but I needed a list that could be sorted: a list of Comparables.
public class SortedCircularArray<E extends Comparable<E>> {
//any E that implements Comparable or extends a Comparable class
which contains the data member:
private E[] data;
But our new class throws java.lang.ClassCastException:
#SuppressWarnings("unchecked")
private E[] newArray(int size)
{
//Old: return (E[]) new Object[size]; //Create an array of Objects then cast it as E[]
return (E[]) new Comparable[size]; //A comparable is an object, but the converse may not be
}
In the constructor everything is the same:
data = newArray(INITIAL_CAPACITY); //Done for reusability
I hope this helps and I hope our more experienced users will correct me if I've made mistakes.
From Oracle tutorial [sic]:
You cannot create arrays of parameterized types. For example, the following code does not compile:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
The following code illustrates what happens when different types are inserted into an array:
Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.
If you try the same thing with a generic list, there would be a problem:
Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it.
If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.
To me, it sounds very weak. I think that any programmer with a sufficient understanding of generics, would be perfectly fine, and even expect, that the ArrayStoredException is not thrown in such case.
Even more, most programmers will simply do:
List<Integer> arrayOfLists = (List<Integer>) new List[2];
which will put them in exactly the same risk of ArrayStoreException not thrown.
As far my knowledge
Frist try to create an array of java.lang.Object and then cast to Generic type T
Example:
class Example<DataType>{
public DataType array = (DataType[]) new Object[5] ;
}
In this way, you can create an array of generic datatype
#SuppressWarnings("unchecked")
private Map<String,?>[] newArray(int n) {
return new Map[n];
}
using with a Stream of Map<String,?>:
sql.executeBatch(myStream.toArray(this::newArray));
using with a List of Map<String,?>:
sql.executeBatch(myList.toArray(newArray(0));
NOTE: the SuppressWarnings trick is actively used in JDK src - https://github.com/AdoptOpenJDK/openjdk-jdk14/blob/master/src/java.base/share/classes/java/util/ArrayList.java#L395:L404
Credits to: #JonathanCallen
I try to add objects to a List<String> instance but it throws an UnsupportedOperationException.
Does anyone know why?
My Java code:
String[] membersArray = request.getParameterValues('members');
List<String> membersList = Arrays.asList(membersArray);
for (String member : membersList) {
Person person = Dao.findByName(member);
List<String> seeAlso;
seeAlso = person.getSeeAlso();
if (!seeAlso.contains(groupDn)){
seeAlso.add(groupDn);
person.setSeeAlso(seeAlso);
}
}
The error message:
java.lang.UnsupportedOperationException
java.util.AbstractList.add(Unknown Source)
java.util.AbstractList.add(Unknown Source)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Not every List implementation supports the add() method.
One common example is the List returned by Arrays.asList(): it is documented not to support any structural modification (i.e. removing or adding elements) (emphasis mine):
Returns a fixed-size list backed by the specified array.
Even if that's not the specific List you're trying to modify, the answer still applies to other List implementations that are either immutable or only allow some selected changes.
You can find out about this by reading the documentation of UnsupportedOperationException and List.add(), which documents this to be an "(optional operation)". The precise meaning of this phrase is explained at the top of the List documentation.
As a workaround you can create a copy of the list to a known-modifiable implementation like ArrayList:
seeAlso = new ArrayList<>(seeAlso);
Many of the List implementation support limited support to add/remove, and Arrays.asList(membersArray) is one of that. You need to insert the record in java.util.ArrayList or use the below approach to convert into ArrayList.
With the minimal change in your code, you can do below to convert a list to ArrayList. The first solution is having a minimum change in your solution, but the second one is more optimized, I guess.
String[] membersArray = request.getParameterValues('members');
ArrayList<String> membersList = new ArrayList<>(Arrays.asList(membersArray));
OR
String[] membersArray = request.getParameterValues('members');
ArrayList<String> membersList = Stream.of(membersArray).collect(Collectors.toCollection(ArrayList::new));
Form the Inheritance concept, If some perticular method is not available in the current class it will search for that method in super classes. If available it executes.
It executes AbstractList<E> class add() method which throws UnsupportedOperationException.
When you are converting from an Array to a Collection Obejct. i.e., array-based to collection-based API then it is going to provide you fixed-size collection object, because Array's behaviour is of Fixed size.
java.util.Arrays.asList( T... a )
Souce samples for conformation.
public class Arrays {
public static <T> List<T> asList(T... a) {
return new java.util.Arrays.ArrayList.ArrayList<>(a); // Arrays Inner Class ArrayList
}
//...
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
//...
}
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
//...
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
private class ListItr extends Itr implements ListIterator<E> {
//...
}
}
Form the above Source you may observe that java.util.Arrays.ArrayList class doesn't #Override add(index, element), set(index, element), remove(index). So, From inheritance it executes super AbstractList<E> class add() function which throws UnsupportedOperationException.
As AbstractList<E> is an abstract class it provides the implementation to iterator() and listIterator(). So, that we can iterate over the list object.
List<String> list_of_Arrays = Arrays.asList(new String[] { "a", "b" ,"c"});
try {
list_of_Arrays.add("Yashwanth.M");
} catch(java.lang.UnsupportedOperationException e) {
System.out.println("List Interface executes AbstractList add() fucntion which throws UnsupportedOperationException.");
}
System.out.println("Arrays → List : " + list_of_Arrays);
Iterator<String> iterator = list_of_Arrays.iterator();
while (iterator.hasNext()) System.out.println("Iteration : " + iterator.next() );
ListIterator<String> listIterator = list_of_Arrays.listIterator();
while (listIterator.hasNext()) System.out.println("Forward iteration : " + listIterator.next() );
while(listIterator.hasPrevious()) System.out.println("Backward iteration : " + listIterator.previous());
You can even create Fixed-Size array form Collections class Collections.unmodifiableList(list);
Sample Source:
public class Collections {
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
}
A Collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data.
#see also
HashMap vs HashTable
Object Serialization uses the Serializable and Externalizable interfaces
You will also get this exception if you attempt to add to a List<T> returned by Collections.singletonList(T o):
Returns an immutable list containing only the specified object. The returned list is serializable.
The JVM does not implement add() for Collections.singletonList
List membersList = Arrays.asList(membersArray);
returns immutable list, what you need to do is
new ArrayList<>(Arrays.asList(membersArray)); to make it mutable
You must initialize your List seeAlso :
List<String> seeAlso = new Vector<String>();
or
List<String> seeAlso = new ArrayList<String>();
You cannot modify a result from a LDAP query. Your problem is in this line:
seeAlso.add(groupDn);
The seeAlso list is unmodifiable.
instead of using add() we can use addall()
{ seeAlso.addall(groupDn); }
add adds a single item, while addAll adds each item from the collection one by one. In the end, both methods return true if the collection has been modified. In case of ArrayList this is trivial, because the collection is always modified, but other collections, such as Set, may return false if items being added are already there.