Can somebody please explain me why I can't cast List<> to ArrayList<> with first approach and I do with second one? Thank you.
First approach:
ArrayList<Task> tmp = ((ArrayList<Task>)mTrackytAdapter.getAllTasks(token));
Second approach:
ArrayList<Task> tmp = new ArrayList<Task>(mTrackytAdapter.getAllTasks(token));
When you do the second one, you're making a new arraylist, you're not trying to pretend the other list is an arraylist.
I mean, what if the original list is implemented as a linkedlist, or some custom list? You won't know. The second approach is preferred if you really need to make an arraylist from the result. But you can just leave it as a list, that's one of the best advantages of using Interfaces!
When you are using second approach you are initializing arraylist with its predefined values.
Like generally we do
**ArrayList listofStrings = new ArrayList<>();
**
Let's say you have an array with values, now you want to convert this array into arraylist.
you need to first get the list from the array using Arrays utils.
Because the ArrayList is concrete type that implement List interface. It is not guaranteed that method asList, will return this type of implementation.
List<String> listofOptions = (List<String>) Arrays.asList(options);
then you can user constructoru of an arraylist to instantiate with predefined values.
ArrayList<String> arrlistofOptions = new ArrayList<String>(list);
So your second approach is working that you have passed values which will intantiate arraylist with the list elements.
More over
ArrayList that is returned from Arrays.asList is not an actual arraylist, it is just a wrapper which doesnt allows any modification in the list.
If you try to add or remove over Arrays.asList it will give you
UnsupportedOperationException
Try running the following code:
List<String> listOfString = Arrays.asList("Hello", "World");
ArrayList<String> arrayListOfString = new ArrayList(listOfString);
System.out.println(listOfString.getClass());
System.out.println(arrayListOfString.getClass());
You'll get the following result:
class java.util.Arrays$ArrayList
class java.util.ArrayList
So, that means they're 2 different classes that aren't extending each other. java.util.Arrays$ArrayList signifies the private class named ArrayList (inner class of Arrays class) and java.util.ArrayList signifies the public class named ArrayList. Thus, casting from java.util.Arrays$ArrayList to java.util.ArrayList and vice versa are irrelevant/not available.
The second approach is clearly wrong if you want to cast. It instantiate a new ArrayList.
However the first approach should work just fine, if and only if getAllTasks return an ArrayList.
It is really needed for you to have an ArrayList ? isn't the List interface enough ? What you are doing can leads to Runtime Exception if the type isn't correct.
If getAllTasks() return an ArrayList you should change the return type in the class definition and then you won't need a cast and if it's returning something else, you can't cast to ArrayList.
Just try this :
ArrayList<SomeClass> arrayList;
public SomeConstructor(List<SomeClass> listData) {
arrayList.addAll(listData);
}
You can cast List<> to ArrayList<> if you understand what you doing. Java compiler won't block it.
But:
It's bad practice to casting parent type to child type (or interface to implementation type) without checking.
This way better:
if (list instanceof ArrayList<Task>) {
ArrayList<Task> arraylist = (ArrayList<Task>) list;
}
Maybe you don't need implementation type as reference. Look SonarQube warning https://sbforge.org/sonar/rules/show/squid:S1319. You can avoid this casting in the most cases.
You can use Guava method:
ArrayList<Task> arraylist = Lists.newArrayList(list);
The first approach is trying to cast the list but this would work only if the List<> were an ArrayList<>. That is not the case. So you need the second approach, that is building a new ArrayList<> with the elements of the List<>
Because in the first one , you're trying to convert a collection to an ArrayList.
In the 2nd one , you just use the built in constructor of ArrayList
May be:
ArrayList<ServiceModel> services = new ArrayList<>(parking.getServices());
intent.putExtra("servicios",services);
import java.util.List;
import java.util.Arrays;
import java.util.*;
public class Merge
{
public static void main(String[] args) {
// This is normal way
// List<Integer> l1 = new ArrayList<Integer>(); l1.add(2); l1.add(5); l1.add(10); l1.add(22);
// List<Integer> l2 = new ArrayList<Integer>(); l2.add(3); l2.add(8); l2.add(15);
//Array.asList only have the list interface, but ArrayList is inherited from List Interface with few more property like ArrayList.remove()
List<Integer> templ1 = Arrays.asList(2,5,10,22);
List<Integer> templ2 = Arrays.asList(3,8,12);
//So creation of ArrayList with the given list is required, then only ArrayList.remove function works.
List<Integer> l1 = new ArrayList<Integer>(templ1);
List<Integer> l2 = new ArrayList<Integer>(templ2);
List<Integer> l3 = new ArrayList<Integer>();
Iterator itr1 = l1.iterator();
while(itr1.hasNext()){
int x = (Integer) itr1.next();
Iterator itr2 = l2.iterator();
while(itr2.hasNext()) {
int y = (Integer) itr2.next();
if(x < y) {
l3.add(x);
break;
}
else{
l3.add(y);
itr2.remove();
}
}
}
Iterator it = l1.iterator();
while (it.hasNext()){
int k = (Integer) it.next();
if (l3.contains(k)){
continue;
}
else{
l3.add(k);
System.out.println(k);
}
}
Iterator itr2 = l2.iterator();
while (itr2.hasNext()){
int k = (Integer) itr2.next();
l3.add(k);
}
System.out.println(l3);
}
}
Related
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.
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 am trying to use the Iterables class to filter an ArrayList, but when I try to cast the result back to the original type I get a ClassCastException at runtime.
// domains is an ArrayList<Domain> which is defined earlier in the class
Iterable<Domain> temp = Iterables.filter(domains, new Predicate<Domain>() {
public boolean apply(Domain input) {
if (input.getName().toLowerCase().contains(filter.toString().toLowerCase())) {
return true ;
} else {
return false;
}
}
}) ;
ArrayList<Domain> filteredDomains = (ArrayList<Domain>) temp ; // Error occurs here
To be complete, I am trying to use this in an Android application with a target of 1.6.
temp is not an ArrayList<Domain>. It is an Iterable<Domain>.
If you absolutely need an ArrayList<Domain> (or a List<Domain> in general), then you need to take a slightly different approach.
First, use Collections2.filter() instead of Iterables.filter(): to produce temp and then create a new ArrayList from the resulting Collection:
Collection<Domain> temp = Collections2.filter(domains, myPredicate) ;
List<Domain> filteredDomains = new ArrayList<Domain>(temp);
But you should really think if you need a List or ArrayList and if a Collection is not enough for what you want. If an Iterable is sufficient (for example if you only iterate over the content), then you can even keep using Iterables.filter().
The real return type is an anonymous class that extends IterableWithToString - and we cannot cast that type to ArrayList.
Here's the implementation on grepcode.
Temp is an Iterable not an ArrayList. Further more an ArrayList is an Iterable but not vice versa. What if you had
Iterable<?> iterable = new HashSet<?>();
You can see why a class cast exception would happen here.
To create an ArrayList from the Iterable you would have to iterate over the iterable itself and add to a new ArrayList
List<Domain> filteredDomains = new ArrayList<Domain>();
for(Iterator<Domain> i = temp.iterator(); i.hasNext();){
filteredDomains.add(i.next());
}
Quick Question...
Can collections in Java hold more than one type? Or do they all have to be the same type?
thanks
Simple answer
Yes.
More detailed answer
You can either use generic collection, without <T> value, for example:
ArrayList a = new ArrayList();
a.add(2);
a.add("String");
Using collections without <T> is a bad habit and most IDEs / compilers give a warning here. You can circumvent it by using a collection of Object, i.e.:
ArrayList<Object> a = new ArrayList<Object>();
Or you can find some common interface or supertype that these element must have in, for example ArrayList<Number> - and you can store various objects that have common Number superclass, i.e. BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short:
ArrayList<Number> a = new ArrayList<Number>();
a.add(2); // integer
a.add(42L); // long
a.add(123.45d); // double
System.out.println(a.toString()); // => [2, 42, 123.45]
Note that it essentially means that a elements are of Number class — i.e. you can't ask to execute subclass-specific methods (for example, Double#isInfinite(), which doesn't exist in Number superclass), although you can typecast in run-time if you somehow know it's safe to typecast:
a.get(2).isInfinite() // compile-time error
((Double) a.get(2)).isInfinite() // => false
((Double) a.get(1)).isInfinite() // run-time error (ClassCastException)
Run-time typecasting is also generally frowned upon, as it effectively circumvents proper compile-time type safety.
Also note that it's impossible to assign (or use) ArrayList<Number> in place of ArrayList<Integer> and vice-versa, i.e. this will fail to compile:
public void printNumbers(ArrayList<Number> list) {
list.forEach(System.out::println);
}
ArrayList<Integer> a = new ArrayList<Integer>();
printNumbers(a); // "incompatible types"
as well as this:
public void printIntegers(ArrayList<Integer> list) {
list.forEach(System.out::println);
}
ArrayList<Number> a = new ArrayList<Number>();
printIntegers(a); // "incompatible types"
To declare a variable to be able to accept both ArrayList<Number> or any of its subclasses, one can use ArrayList<? extends Number> or ArrayList<? super Number> syntax. extends is generally used when you're going to consume (i.e. read) from the object in your method, super is used when you're going to produce (i.e. write). Given that printout is consuming, it's safe to use extends:
public void printNumbers(ArrayList<? extends Number> list) {
list.forEach(System.out::println);
}
ArrayList<Integer> listInt = new ArrayList<Integer>();
printNumbers(listInt); // works
ArrayList<Double> listDbl = new ArrayList<Double>();
printNumbers(listDbl); // also works
There is a good answer in
Difference between <? super T> and <? extends T> in Java for more in-depth explanation.
If you want them to hold any more than one type, use Collection<Object>. However, you won't know what you're getting without doing some if (x instanceof MyType) calls, which are rather inefficient.
They have to be of the same Supertype. So if you have objects of type A, then a Collection<A> can store objects of type A and of every subtype of A.
If you want to allow arbitrary types, then use Collection<Object>, otherwise take the most general appropriate super-class.
However, you will then have to manually cast from the most general type (Object) to the specific type you have in mind. You can use the typeof operator to find out what the type is.
Every Collection classes can contains heterogeneous objects except TreeSet and TreeMap. Since TreeSet and TreeMap stores elements according to some sorting order. so, if objects are of different type it will not be able to sort it because comparison between the objects will not be possible for sorting.
Yes they can but they should not (that's why generics have been put in place since 5th version of jdk) in general store different types, as this is the straight way to errors.
Yes collections in java can hold more than one type as below. But it will throw an exception if done using the following way.
ArrayList al = new ArrayList();
al.add(1);
al.add("name");
al.add(1.2f);
Iterator itr =al.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
Hence it's better to mention the type that you're using. To get rid of the exception the above program can be modified as below.
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(1);
al.add(2);
al.add(3);
Iterator itr =al.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
ArrayList<String> al1 = new ArrayList<String>();
al1.add("Words");
al1.add("Names");
al1.add("Characters");
Iterator itr1 =al1.iterator();
while(itr1.hasNext())
{
System.out.println(itr1.next());
}
You can also use more than these types.
Yes,
My mistake the correct code is this one and
ArrayList<Elements>()=new ArrayList();
or
ArrayList<E>()=new ArrayList();
should be the correct declaration if you want to use Generics in Collection.
class Test
{
public static void main(String[] args)
{
// For Generic class of List
ArrayList<E> arrL1 = new ArrayList<E>();
arrL1.add("stackoverflow");
arrL1.add(1);
Iterator itr1=list.iterator();
while(itr1.hasNext())
{
System.out.println(itr1.next());
}
// for Particular datatype in List
ArrayList<String> list=new ArrayList<String>(); // Creating arraylist
list.add("Ravi"); // Adding object in arraylist
list.add("Vijay");
list.add("Ravi");
list.add("Ajay");
// transversing the values
Iterator itr=list.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
}
}
Output 1
stackoverflow
1
Output 2
Ravi
Vijay
Ravi
Ajay
I believe you can also use Collection<?>.
Yes, you can have more than one datatype in ArrayList of Collection.
class Test
{
public static void main(String[] args)
{
// For Generic class of List
ArrayList<> arrL1 = new ArrayList<>();
arrL1.add("stackoverflow");
arrL1.add(1);
// for Particular datatype in List
ArrayList<String> list=new ArrayList<String>(); // Creating arraylist
list.add("Ravi"); // Adding object in arraylist
list.add("Vijay");
list.add("Ravi");
list.add("Ajay");
// transversing the values
Iterator itr=list.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
}
}
Output 1:
stackoverflow
1
Output 2:
Ravi
Vijay
Ravi
Ajay