Search code examples
javaforeachgeneric-listgeneric-type-argument

Why I cannot directly use for-each loop for generic type list?


I am trying to do a for-each loop to get each element of a generic type List.

so if I first get the result, and do for-each loop, it will be fine.

List<MyClass<Entity>> res = response.getResponses();
MyClass<Entity> entity = res.get(0);

for(MyClass<Entity> a : res){
    System.out.println(a);
}

But if I want to direct fo the for-each loop, the IDE will complain that "Incompatible class. Required Object, Found MyClass"


for(MyClass<Entity> a : response.getResponses()){
    System.out.println(a);
}

And I cannot use T as some posts elsewhere suggest. The IDE would show "Cannot resolve symbol 'T'"

for(MyClass<T> a : response.getResponses()){
    System.out.println(a);
}

EDIT: Following is response class definition

public class Response<T> {
    private List<MyClass<T>> responses;

    public Response(List<MyClass<T>> responses) {
        this.responses = responses;
    }

    public List<MyClass<T>> getResponses() {
        return this.responses;
    }
}

And the returned type is actually an API call, I debugged and found out it should be of an Entity type.

Any idea about why?


Solution

  • I can't give a personal answer to solve it without seeing more of your code base, but the actual issue is apparent.

    Response is a class with a generic type. https://www.baeldung.com/java-generics

    Reading that article before proceeding, it's generally good info to have in java, and the rest of this answer won't make sense without it.

    T doesn't extend anything, so by default it extends Object. That's why if you do ArrayList myList it's equivalent to ArrayList<Object> myList. If you can change Response, you can update the generic to be <T extends Entity> and it'll work. That's assuming that every generic object T is going to be some sort of entity object.

    The problem is at some point in your program you're losing the specifics on what the object is, consider this.

    Response r = new Response();
    List<Response<Entity>> list = r.getResponses();
    

    The problem with that code is you're expecting a Response, but since type was never specified it defaults to Response<Object> r = new Response(). and while it may technically be returning Response under the hood, the compiler doesn't know that for sure.