ClassCastException using Iterables from Guava - java

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());
}

Related

Changing from List to ArrayList removes the error "List is an abstract and can not be instantiated?

Well, I'm new to List I've always worked with Arrays, now I'm writing a program where I cannot tell the size of the array before it's creation so I'm using List. The thing is that I've a method that returns a List of none repeating digits.
Here is my method:
public static List<Integer> arrayOfNoneRepeatingDigits(int limit) {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < limit; i++){
boolean ignore = false;
for(int j = i; j > 0; j/=10){
if(ignore == true) break;
for(int k = j/10; k > 0; k/=10){
if(j%10 == k%10){
ignore = true;
break;
}
}
}
if(ignore == false)list.add(i);
}
return list;
}
First my method datatype was an Array but after I changed it to List this line of code gave an error:
List<Integer> list = new List<Integer>();
I've searched online and It turned out that I should replace List with ArrayList. I did it and the error is gone now but I don't know why.
Interfaces cannot be instantiated, so no new List<Integer> stuff. Interfaces's methods don't have implementations. The implementations of those methods are in the subclasses. ArrayList is one of the subclasses of List so that's why you can use your first code snippet.
If you write new List<Integer>, it doesn't make sense. Because List's methods don't have implementations so when you call the add method, how would the compiler know what implementation is in the method?
This:
List<Integer> list = new List<Integer>();
doesn't make sense since you're trying to directly instantiate an interface, something that is not concrete and thus something that you can't do unless you create an anonymous inner class with the instantiation, something that you really don't want to do. The best solution: stick with the ArrayList for the concrete implementation (or LinkedList depending on your requirements). e.g.,
List<Integer> list = new ArrayList<>();
Out of curiosity, what motivated you to make this change when you already had working code?
List is an interface. It means there is no attribute in List, and methods are declared but not defined. So, there is not enough information to instantiate it and an error occurs. This happens same when you try to instantiate an object of an abstract class.
You can declare an object of interface/abstract class, but you cannot instantiate it. So you have two choices.
List<Integer> list = new ArrayList<Integer();
((ArrayList)list).method();
//cast it into ArrayList.
//If you try to cast a wrong class, then the error will be printed out.
This way need extra casting. Else, you can declare with ArrayList also.
ArrayList<Integer>list = new ArrayList<Integer>();

How to return an interface from a method

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(){}

Object without any content/empty Object

while developing I was trying to return an empty List.
public Collection<?> getElements() {
// return elements
}
I searched for an easy way, my first idea was to create for example an ArrayList without any elements and return it. Like the following example:
public Collection<?> getElements() {
return new ArrayList<?>();
}
For me it is too much overhead for an empty list.
There is a really simple solution for the above described "problem":
public Collection<?> getElements() {
return Collections.EMPTY_LIST;
}
That returns an empty list.
Notice:
It returns an immutable object! You can use it only, if you need an object, which isn't editable.
Type-safety
In the case you want to get a type-safe list you should use the following example [1]:
List<String> s = Collections.emptyList();
Three kinds of interfaces are supported:
List:
List l = Collections.EMPTY_LIST;
List<String> s = Collections.emptyList();
Map:
Map m = Collections.EMPTY_MAP;
Map<String> ms = Collections.emptyMap();
Set:
Set s = Collections.EMPTY_SET;
Set<String> ss = Collections.emptySet();
Notice:
Implementations of this method need not create a separate XXX object
for each call. Using this method is likely to have comparable cost to
using the like-named field. (Unlike this method, the field does not
provide type safety.)

How to return the correct type of list?

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;
}

How to cast ArrayList<> from List<>

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);
}
}

Categories

Resources