I want to initialize a Set Implementation (HashSet) in Java with an Iterable. However, the constructor of HashSet doesn't accept Iterables, but only Collections type objects.
Is there a way to convert from Iterable to some subtype of Collections.
You can use Guava.
Set<T> set = Sets.newHashSet(iterable);
or to make it read like a sentence static import,
import static com.google.common.collect.Sets.*;
Set<T> set = newHashSet(iterable);
HashSet constructor relies on more than what Iterable offers: it wants to know the size of the collection up front in order to optimally construct the underlying HashMap. If you have a true, austere Iterable, which doesn't know its size, then you'll have to realize the Iterable up front by turning it into a regular Collection in any of a number of obvious ways.
If, on the other hand, you have a richer object that already knows its size, then it would pay to create a minimalist adapter class that wraps your Iterable into a collection, implementing just size in addition to forwarding the call to iterator.
public class IterableCollection<T> implements Collection<T>
{
private final Iterable<T> iterable;
public IterableCollection(Iterable<T> it) { this.iterable = it; }
#Override public Iterator<T> iterator() { return iterable.iterator(); }
#Override public int size() { return ... custom code to determine size ... }
#Override .... all others ... { throw new UnsupportedOperationException(); }
}
Sure, it's shown in this answer. Basically, iterate over the iterable and copy its contents in a collection:
public static <T> List<T> copyIterable(Iterable<T> iterable) {
Iterator<T> iter = iterable.iterator();
List<T> copy = new ArrayList<T>();
while (iter.hasNext())
copy.add(iter.next());
return copy;
}
Use it as follows, the resulting List object can be passed as a parameter to the HashSet constructor.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> copy = copyIterable(list);
Set<Integer> aSet = new HashSet<Integer>(copy);
EDIT
I've been mistaken all along. Iterable is a superinterface of Collection, so a simple (but unsafe) cast will do the trick, as long as the Iterable was a Collection to begin with.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works!
The Iterable interface allows the "foreach" syntax to work, so the cleanest way is likely:
public <T> Set<T> toSet(Iterable<T> collection) {
HashSet<T> set = new HashSet<T>();
for (T item: collection)
set.add(item);
return set;
}
Just add each one.
public static <T> Set<T> setFromIterable(Iterable<T> i) {
HashSet<T> set = new HashSet<T>();
Iterator<T> it = i.iterator();
while (it.hasNext()) {
set.add(it.next());
}
return set;
}
Iterable<Integer> someIterable = ...;
Set<Integer> someSet = setFromIterable(someIterable);
Note that you don't use the constructor new HashSet<Integer>(someIterator), because that doesn't exist. Just call the static method.
I use this one-liner (with Java 8+), which only relies on java.util.stream:
StreamSupport.stream(myIterable.spliterator(), false).collect(Collectors.toSet());
// or with static imports:
stream(myIterable.spliterator(), false).collect(toSet());
Putting somewhat a repeated answer for conciseness. Below worked for me for converting the Iterable of String type to a Set(Java8).
Iterable<String> stringIterable = Arrays.asList("str1", "str2", "str3");
Set<String> stringHashSet = new HashSet<>((Collection<? extends String>) stringIterable);
Related
I have this:
private ArrayList<ArrayList<Object>> models;
and in the constructor I have:
models = new ArrayList<ArrayList<Object>>();
Later, I do things like:
models.add(new ArrayList<Object>());
as well as other operations.
I want to make the external ArrayList to something with a fixed size (Array, List) and I am really lost to how I am going to write the declaration, initialization, addition, etc. because of the nested objects. Can someone save me time by answering this for me?
You can use Arrays.asList() to created fixed sized Lists.
Examples:
A List of size 3, initialized with null values:
List<ArrayList<Object>> models = Arrays.asList (null,null,null);
A List of size 3, initialized with non-null values:
List<ArrayList<Object>> models = Arrays.asList (new ArrayList<Object> (),new ArrayList<Object> (),new ArrayList<Object> ());
A List of size 10, initialized with null values:
List<ArrayList<Object>> models = Arrays.asList ((ArrayList<Object>[])new ArrayList[10]);
Note that add operation is not supported for fixed sized lists. You'll have to use models.set(index,new ArrayList<Object>()) instead.
EDIT:
Here's another way to initialize the List using Streams:
List<ArrayList<Object>> models = Arrays.asList (Stream.generate (ArrayList::new).limit (10).toArray (ArrayList[]::new));
A slightly more verbose - but generic-compatible way - of doing it is to extend AbstractList.
The methods you need to override are described in the Javadoc:
To implement an unmodifiable list, the programmer needs only to extend this class and provide implementations for the get(int) and size()methods.
To implement a modifiable list, the programmer must additionally override the set(int, E) method (which otherwise throws an UnsupportedOperationException).
So, implement these three methods, delegating to an ArrayList:
class FixedSizedList<T> extends AbstractList<T> {
private final List<T> delegate;
FixedSizedList(int size) {
delegate = new ArrayList<>(Collections.nCopies(size, null));
}
public T get(int i) { return delegate.get(i); }
public int size() { return delegate.size(); }
public T set(int i, T e) { return delegate.set(i, e); }
}
Or, for that matter, just use an array:
class FixedSizedList<T> extends AbstractList<T> {
private final Object[] array;
FixedSizedList(int size) {
array = new Object[size];
}
public T get(int i) { return (T) array[i]; }
public int size() { return array.length; }
public T set(int i, T e) {
T old = (T) array[i];
array[i] = e;
return old;
}
}
There isn't an Array class in java, but there is the plain old array declaration:
ArrayList<Object> [] array...
Problem is that you will not be able to instantiate it like this, since arrays can not be generic.
You are really looking for either Arrays.asList or much better ImmutableList of some kind.
public static <T> List<T> arrayListReverse(List<T> lst) {
ArrayList reversed= new ArrayList();
for (int i=lst.size()-1;i>=0;i--){
<T> t= lst.get(i);
reversed.add(t);
}
return reversed;
}
I want to be be able to return a list that is a reversed version of the original list. It should be able to work for any type. I keep getting errors when it comes to the t=input.get(i);
Edit: I would like to only use the List interface
public static <T> List<T> arrayListReverse(List<T> lst) {
Collections.reverse(lst);
return lst;
}
<T> should be T:
public static <T> List<T> arrayListReverse(List<T> lst) {
ArrayList reversed= new ArrayList();
for (int i=lst.size()-1;i>=0;i--){
T t = lst.get(i);
reversed.add(t);
}
return reversed;
}
In your code <T> t = should just be T t =, but you could also use a for-each loop and add to the front of your reversed as you iterate forward. And, you shouldn't use raw types (you didn't specify a generic for reversed) and you could use the diamond operator <>. And you could initialize your output list with the same initial size as your input. Something like
public static <T> List<T> arrayListReverse(final List<T> lst) {
List<T> reversed = new ArrayList<>(lst.size());
for (T t : lst) {
reversed.add(0, t);
}
return reversed;
}
You can also use this:
ArrayList reversed = new ArrayList();
reversed=Collections.reverse(startArray);
Documentation:
public static void reverse(List list)
Reverses the order of the elements in the specified list.
This method runs in linear time.
Parameters:
list - the list whose elements are to be reversed.
Throws:
UnsupportedOperationException - if the specified list or its list-iterator does not support the set operation.
If you really want the method to return the same type of list, as is given as parameter, use the following:
public static <T,L extends List<T>> L reverse(L list){
Collections.reverse(list);
return list;
}
This will return a Vector<String>, if you pass a Vector of Strings.
It will return an ArrayList<Something>, if you pass an ArrayList of Somethings.
It will return a LinkedList<Doom>, when you pass a LinkedList of Doom.
I think, you get the idea.
Btw., Madushan Perera`s answer will also return the same Type as passed, but in that case you would have to cast, if assigning to the original variable.
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 }
If I have a method like this (for simplicity assume integers):
public static List<Integer> doSomething(List<Integer> list) {
// logic here
}
and I need for my processing to create internally a new list which I will create and somehow populate and return to the caller, how can I do it since I don't know what type of list the caller passed in?
I don't want to return a List of different type that what the caller passed in.
E.g. If the caller passed a LinkedList and I don't want to return an ArrayList.
How can this issue best be approached?
You shouldn't tie your implementation to a particular implementation of List, the idea of using an interface is that, from the outside, it shouldn't matter what concrete class you're instantiating as long as it conforms to the List interface.
EDIT :
Anyway, here's a possible way:
List<Integer> lst1 = new ArrayList<Integer>();
Class<?> klass1 = lst1.getClass();
List<Integer> copy1 = (List<Integer>) klass1.newInstance();
System.out.println(copy1.getClass().getName());
> java.util.ArrayList
List<Integer> lst2 = new LinkedList<Integer>();
Class<?> klass2 = lst2.getClass();
List<Integer> copy2 = (List<Integer>) klass2.newInstance();
System.out.println(copy2.getClass().getName());
> java.util.LinkedList
As you can see in the console, the copies are instances of the same class as the original list.
If you can get away with just using one of those two output types, then you can do
if (inputList instanceof RandomAccess) {
// use an ArrayList
} else {
// use a LinkedList.
}
The RandomAccess interface is meant to indicate that the implementation allows O(1) get operations.
Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.
By doing this, your APIs allow clients to defend their inputs. They can pass in the result of Collections.unmodifiableList(...) and be sure that it isn't modified by other code.
If you really know the input is a mutable list, you can clone() the list, then clear() it. Both ArrayList and LinkedList have public clone() methods which can be accessed reflectively.
The best thing to do is to remove the list creation from the method. Have the caller decide how to create the list:
public static void doSomething(List<Integer> dest, List<Integer> src) {
You could use Class.newInstance to create a list of the passed in type:
public static List<Integer> doSomething(List<Integer> list)
{
List<Integer> newList = null;
try
{
newList = list.getClass().newInstance();
}
catch(InstantiationException e)
{
throw new RuntimeException(e);
}
catch(IllegalAccessException e)
{
throw new RuntimeException(e);
}
//Logic here
return newList;
}
#Test
public void test()
{
List<Integer> testList = new ArrayList<Integer>();
List<Integer> resultList = doSomething(testList);
Assert.assertEquals(testList.getClass(), resultList.getClass());
Assert.assertNotSame(LinkedList.class, resultList.getClass());
testList = new LinkedList<Integer>();
resultList = doSomething(testList);
Assert.assertEquals(testList.getClass(), resultList.getClass());
Assert.assertNotSame(ArrayList.class, resultList.getClass());
}
If you really, really care what kind of object comes out, I would include that as a parameter to the method, like:
<T extends List<Integer>> T doSomething(Class<T> returnType,List<Integer> v)
throws Exception
{
// constructors for your return will be tricky :)
// returnType.newInstance() will probably work.
T result = returnType.newInstance();
result.add(86); result.add(99);
return result;
}
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.