Can a List<T> be initialized to contain a given number of nulls, where T is a type parameter of the class of which the list is a member? I sure can do it with a loop, but like to know whether it is possible without.
List<T> myList = new ArrayList<T>(numEls);
creates a list of the given capacity, but size 0, so myList.get(x) fails for all x, and so does, e.g. myList.set(numEls-1,null).
myList = Arrays.asList(new T[numEls]);
does not compile, and
myList = (List<T>) Arrays.asList(new Object[numEls]);
compiles in Eclipse (with an Unchecked cast warning), but not with javac.
Update: Thank you for the answers! However, I found another, quite short, solution close to my last attempt above, which compiles both in eclipse and with our automated build system: Cast the array, not the list!
myList = Arrays.asList((T[]) new Object[numEls]);
If you don't need to mutate the list...
List<T> result = Collections.nCopies(num, (T) null);
... or alternately
List<T> result = new ArrayList<T>(Collections.nCopies(num, (T) null));
You would need to use reflection to instantiate a backing array T[] using Array.newInstance():
public static <T> List<T> getListWithNulls(Class<T> componentType, int length) {
T[] array = (T[])Array.newInstance(componentType, length);
return new ArrayList<T>(Arrays.asList(array));
}
As you can see, this requires a reference to the Class<T> object representing the type of T:
List<String> strListWithNulls = getListWithNulls(String.class, 100);
Also make sure not to confuse the classes java.lang.reflect.Array and java.util.Arrays which are both used here.
Finally, note that reflection is going to be much slower than just using a loop.
Not really a solution, but you wanted to avoid a loop.
void fillNullList(List<T> list, count) {
if (count > 0) {
list.add(null);
fillNullList(list, count - 1);
}
}
Seriously, why do you want to avoid a loop? Probably, you want a solution with O(1) complexity and not a O(n) complexity solution regardless if a loop is used for not.
What you probably want is something like this....
final int maxSize = 50;
List<T> v = new Vector<T>() {{setSize(maxSize);}};
Vectors allow you to set a size, which fills them with null's.
I would just use a loop, its simpler and likely to be faster as well.
List<T> list =
while(list.size()<size) list.add(null);
Any other approach you use is likely to use a loop for you. If this is fine, just write your own method which hides the loop used.
new option with streams:
List resultColumn = IntStream.range(0, 10000).mapToObj(i -> null).collect(Collectors.toList());
Try this:
List<String> list = new ArrayList<String>(Arrays.asList(new String[100]));
for(String string : list){
System.out.println(string);
}
Well, you can write a hierarchy:
class Base<T>{
protected List<T> list;
public List<T> getList(){
return list;
}
}
class Child extends Base<String>{
public Child(){
list = new ArrayList<String>(Arrays.asList(new String[100]));
}
}
It can be used in the next way:
Base<String> base = new Child();
base.getList();
What I did was
MyClass[] array = {new MyClass(), new MyClass(), new MyClass(), new MyClass(), new ProfileSectionDTO(), new MyClass()};
List<MyClass> MyClassList = Arrays.asList(array);
Dirty, but working :)
if you want an ArrayList you can use reflection to cheat
ArrayList<T> myList = new ArrayList<T>(numEls);
Field f = ArrayList.class.getField("size");//cache this
f.setAccessible(true);
f.setInt(myList, numEls);
Related
I need an immutable list where I can get derive a second immutable list preserving all elements of the previous list plus an additional element in Java (without additional libraries).
Note: This question is similar to What is an efficient and elegant way to add a single element to an immutable set? but I need a list and don't have Guava.
What I have tried so far:
var list = List.of(someArrayOfInitialElements);
var newList = Stream.concat(list.stream(), Stream.of(elementToAppend))
.collect(CollectorsCollectors.toUnmodifiableList());
That would work but creating a stream and copying elements one by one seems inefficient to me. You could basically bulk copy memory given that List.of() stores data in a field-based or array-based data structure.
Is there a more efficient solution than using streams? A better data structure in the Java standard library that I am missing?
I would create a new ArrayList append the element and then return that as an unmodifiable list. Something like,
private static <T> List<T> appendOne(List<T> al, T t) {
List<T> bl = new ArrayList<>(al);
bl.add(t);
return Collections.unmodifiableList(bl);
}
And to test it
public static void main(String[] args) {
List<String> al = appendOne(new ArrayList<>(), "1");
List<String> bl = appendOne(al, "2");
System.out.println(bl);
}
I get (unsurprisingly):
[1, 2]
See this code run at IdeOne.com.
The Answer by Frisch is correct, and should be accepted. One further noteā¦
Calling Collections.unmodifiableList produces a collection that is a view onto the original mutable list. So a modification to the original list will "bleed through" to the not-so-immutable second list.
This issue does not apply to the correct code shown in that Answer, because the new ArrayList object deliberately goes out-of-scope. Therefore that new list cannot be accessed for modification. But in other coding scenarios, this issue could be a concern.
List.copyOf
If you want an independent and truly immutable second list, use List.copyOf in Java 10+. This returns an unmodifiable list.
return List.copyOf( bl ) ;
Both answers are great, I would create a bit more generic solution:
private static <T> List<T> append(final List<T> al, final T... ts) {
final List<T> bl = new ArrayList<>(al);
for (final T t : ts) {
bl.add(t);
}
return List.copyOf(bl);
}
It can be used exactly like previous answer:
List<String> al = append(new ArrayList<>(), "1");
List<String> bl = append(al, "2");
System.out.println(bl);
But also slightly more efficient:
List<String> bl = append(new ArrayList<>(), "1", "2");
System.out.println(bl);
I am trying do something like this:-
public static ArrayList<myObject>[] a = new ArrayList<myObject>[2];
myObject is a class. I am getting this error:- Generic array creation (arrow is pointing to new.)
You can't have arrays of generic classes. Java simply doesn't support it.
You should consider using a collection instead of an array. For instance,
public static ArrayList<List<MyObject>> a = new ArrayList<List<MyObject>();
Another "workaround" is to create an auxilliary class like this
class MyObjectArrayList extends ArrayList<MyObject> { }
and then create an array of MyObjectArrayList.
Here is a good article on why this is not allowed in the language. The article gives the following example of what could happen if it was allowed:
List<String>[] lsa = new List<String>[10]; // illegal
Object[] oa = lsa; // OK because List<String> is a subtype of Object
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[0] = li;
String s = lsa[0].get(0);
There is a easier way to create generic arrays than using List.
First, let
public static ArrayList<myObject>[] a = new ArrayList[2];
Then initialize
for(int i = 0; i < a.length; i++) {
a[i] = new ArrayList<myObject>();
}
You can do
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList<?>[2];
or
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList[2];
(The former is probably better.) Both will cause unchecked warnings, which you can pretty much ignore or suppress by using: #SuppressWarnings("unchecked")
if you are trying to declare an arraylist of your generic class you can try:
public static ArrayList<MyObject> a = new ArrayList<MyObject>();
this will give you an arraylist of myobject (size 10), or if u only need an arraylist of size 2 you can do:
public static ArrayList<MyObject> a = new ArrayList<MyObject>(2);
or you may be trying to make an arraylist of arraylists:
public static ArrayList<ArrayList<MyObject>> a = new ArrayList<ArrayList<MyObject>>();
although im not sure if the last this i said is correct...
It seems to me that you use the wrong type of parenthesis. The reason why you can't define an array of generic is type erasure.
Plus, declaration of you variable "a" is fragile, it should look this way:
List<myObject>[] a;
Do not use a concrete class when you can use an interface.
I am trying do something like this:-
public static ArrayList<myObject>[] a = new ArrayList<myObject>[2];
myObject is a class. I am getting this error:- Generic array creation (arrow is pointing to new.)
You can't have arrays of generic classes. Java simply doesn't support it.
You should consider using a collection instead of an array. For instance,
public static ArrayList<List<MyObject>> a = new ArrayList<List<MyObject>();
Another "workaround" is to create an auxilliary class like this
class MyObjectArrayList extends ArrayList<MyObject> { }
and then create an array of MyObjectArrayList.
Here is a good article on why this is not allowed in the language. The article gives the following example of what could happen if it was allowed:
List<String>[] lsa = new List<String>[10]; // illegal
Object[] oa = lsa; // OK because List<String> is a subtype of Object
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[0] = li;
String s = lsa[0].get(0);
There is a easier way to create generic arrays than using List.
First, let
public static ArrayList<myObject>[] a = new ArrayList[2];
Then initialize
for(int i = 0; i < a.length; i++) {
a[i] = new ArrayList<myObject>();
}
You can do
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList<?>[2];
or
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList[2];
(The former is probably better.) Both will cause unchecked warnings, which you can pretty much ignore or suppress by using: #SuppressWarnings("unchecked")
if you are trying to declare an arraylist of your generic class you can try:
public static ArrayList<MyObject> a = new ArrayList<MyObject>();
this will give you an arraylist of myobject (size 10), or if u only need an arraylist of size 2 you can do:
public static ArrayList<MyObject> a = new ArrayList<MyObject>(2);
or you may be trying to make an arraylist of arraylists:
public static ArrayList<ArrayList<MyObject>> a = new ArrayList<ArrayList<MyObject>>();
although im not sure if the last this i said is correct...
It seems to me that you use the wrong type of parenthesis. The reason why you can't define an array of generic is type erasure.
Plus, declaration of you variable "a" is fragile, it should look this way:
List<myObject>[] a;
Do not use a concrete class when you can use an interface.
This is a Java question.
What is the fastest way to convert a List<?> to a List<ObjectType>? I am aware that this is possible through iteration please exclude that option.
Example by iteration,
final List<ObjectType> targetList = new ArrayList<ObjectType>();
// API returns List<?> so I have no choice.
List<?> resultList = resultSet.getResults();
// This is slow. Average list size is 500,000 elements.
while (resultList != null && !resultList.isEmpty()) {
for (final Object object : resultList) {
final ObjectType objectType = (ObjectType) object;
targetList.add(objectType);
}
resultSet = someService.getNext(resultSet);
resultList = resultSet.getList();
}
Thanks.
It's a bit scary but depending on context you could possibly get away with just casting:
final List<ObjectType> targetList = (List<ObjectType>)problemSolver.getResults();
As Tom said above, if you know for a fact that everything in the original List<?> is an ObjectType -- as implied by the iteration code -- casting to List<ObjectType> will work just fine.
The only difference from the iteration code is that, if anything's not an ObjectType, in the iteration code the ClassCastException will happen when you're populating targetList, while with the straight cast, it'll happen when you're getting the values out. E.g.:
public static void main(String[] args) {
List<?> list = Arrays.<Object> asList('I', "am", "not", "homogeneous");
List<Character> targetList = (List<Character>) list;
int index = 0;
try {
for (Character c : targetList) {
System.out.println(c);
index++;
}
} finally {
System.out.println("Reached " + index);
}
}
prints
I
Exception in thread "main" java.lang.ClassCastException: java.lang.String
cannot be cast to java.lang.Character
at Foo.main(Foo.java:100)
Reached 1
Umm... if you are really dealing with 500,000 elements and expreriencing a performance issue, I'd bite the bullet (the bullet being compiler's "unchecked" warning) and cast it:
List<ObjectType> targetList = new ArrayList<ObjectType>((List<ObjectType>) resultList);
You can then use #SuppressWarnings("unchecked") annotation to suppress the warning.
The above is, of course, assuming that resultList does not satisfy you in some way (perhaps it's unmodifiable or array-backed or what have you). Otherwise you can simply cast it.
The correct solution depends on whether you want to ensure that the elements you put into targetList really are instances of ObjectType (or a subtype).
If you don't care, one of the solutions with an unsafe typecast will do. Unless you need to copy, #Toms solution is better. (You might need to copy if getResults() returns a linked list and your algorithm needs to use targetList.get(int) a lot.) But beware that you might get an unexpected ClassCastException later on if your assumptions are incorrect.
If you need to be sure that there are no elements of the wrong type, then you have to use an iterator-based solution unless you know what kind of List type that getResults() gives you. (If you can cast the result of getResults() to ArrayList, then indexing using get(int) should be faster than using an Iterator. On the other hand, if the result is a LinkedList, then using get(int) to copy the list is O(N**2)!!)
How about this?
final List<?> resultList = problemSolver.getResults();
List<ObjectType> targetList;
if (resultList == null || resultList.isEmpty()) {
targetList = Collections.empyList();
} else {
int len = resultList.size();
// it is important to preallocate the ArrayList with the
// right size ... to conserve space and avoid copy on realloc
// of the list's private backing array.
targetList = new ArrayList<ObjectType>(len);
if (resultList instanceof ArrayList) {
// Copy using indexing - O(N) for ArrayLists
ArrayList<?> arrayList = (ArrayList) resultList;
for (int i = 0; i < len; i++) {
targetList.add((ObjectType) (arrayList.get(i)));
}
} else {
// Copy using iterator - O(N) for all sane List implementations,
// but with a larger C than the best case for indexing.
for (Object obj : resultList) {
targetList.add((ObjectType) obj);
}
}
}
What's wrong with iteration?
But as you wish:
final List<?> src = ...;
final int len = src.size();
final SomeType[] dstArray = new SomeType[len];
src.<SomeType>toArray(dstArray);
final List<SomeType> dst = java.util.Arrays.asList(dstArray);
Or:
(Disclaimer: Not so much as compiled.)
I prefer the iteration method.
public class MyGraph<V,E> extends SparseMultigraph<V,E>{
private ArrayList<MyNode> myNodeList;
public MyNode getNode(int nodeId){
myNodeList = new ArrayList<MyNode>();
myNodeList = (ArrayList<MyNode>)this.getVertices();
int i;
The following are the error msg:
Exception in thread "main" java.lang.ClassCastException:
java.util.Collections$UnmodifiableCollection cannot be cast to
java.util.ArrayList...
Can anyone help?
As other people have mentioned, ArrayList has a constructor that takes a collection of items, and adds all of them. Here's the documentation:
http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html#ArrayList%28java.util.Collection%29
So you need to do:
ArrayList<MyNode> myNodeList = new ArrayList<MyNode>(this.getVertices());
However, in another comment you said that was giving you a compiler error. It looks like your class MyGraph is a generic class. And so getVertices() actually returns type V, not type myNode.
I think your code should look like this:
public V getNode(int nodeId){
ArrayList<V> myNodeList = new ArrayList<V>(this.getVertices());
return myNodeList(nodeId);
}
But, that said it's a very inefficient way to extract a node. What you might want to do is store the nodes in a binary tree, then when you get a request for the nth node, you do a binary search.
Try this code
Convert ArrayList to Collection
ArrayList<User> usersArrayList = new ArrayList<User>();
Collection<User> userCollection = new HashSet<User>(usersArrayList);
Convert Collection to ArrayList
Collection<User> userCollection = new HashSet<User>(usersArrayList);
List<User> userList = new ArrayList<User>(userCollection );
public <E> List<E> collectionToList(Collection<E> collection)
{
return (collection instanceof List) ? (List<E>) collection : new ArrayList<E>(collection);
}
Use the above method for converting the collection to list
The following code will fail:
List<String> will_fail = (List<String>)Collections.unmodifiableCollection(new ArrayList<String>());
This instead will work:
List<String> will_work = new ArrayList<String>(Collections.unmodifiableCollection(new ArrayList<String>()));
More information needed for a definitive answer, but this code
myNodeList = (ArrayList<MyNode>)this.getVertices();
will only work if this.getVertices() returns a (subtype of) List<MyNode>. If it is a different collection (like your Exception seems to indicate), you want to use
new ArrayList<MyNode>(this.getVertices())
This will work as long as a Collection type is returned by getVertices.