27

Please consider the following snippet:

public interface MyInterface {

    public int getId();
}

public class MyPojo implements MyInterface {

    private int id;

    public MyPojo(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

}

public ArrayList<MyInterface> getMyInterfaces() {

    ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return (ArrayList<MyInterface>) myPojos;
}

The return statement does a casting that doesn't compile. How can I convert the myPojos list to the more generic list, without having to go through each item of the list?

Thanks

Ry.
  • 405
  • 2
  • 5
  • 8

6 Answers6

42

Change your method to use a wildcard:

public ArrayList<? extends MyInterface> getMyInterfaces() {    
    ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

This will prevent the caller from trying to add other implementations of the interface to the list. Alternatively, you could just write:

public ArrayList<MyInterface> getMyInterfaces() {
    // Note the change here
    ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

As discussed in the comments:

  • Returning wildcarded collections can be awkward for callers
  • It's usually better to use interfaces instead of concrete types for return types. So the suggested signature would probably be one of:

    public List<MyInterface> getMyInterfaces()
    public Collection<MyInterface> getMyInterfaces()
    public Iterable<MyInterface> getMyInterfaces()
    
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • The 2nd solution is better one IMHO. Returning wild cards is generally considered bad practice, b/c it constrains the client code. In this case with ArrayList extends MyInterface> you could only read from the list, and could not add anything to it. – Julien Chastang Mar 19 '09 at 16:08
  • That may be what's wanted, of course - we just don't know. (It should almost certainly use List instead of ArrayList as well, or possibly just Iterable or Collection.) – Jon Skeet Mar 19 '09 at 16:15
  • 1
    +1 for using more generic types (e.g. List, Collection). But returning wildcards is rarely what you want. If you are leaning towards immutability there are better ways of doing it. Naftalin & Wadler talk about this in "Java Generics and Collections". – Julien Chastang Mar 19 '09 at 16:21
  • Java's handling of generics is terrible compared to C#. It should be perfectly valid to add a Dog to a list of Animals. – csmith Oct 02 '16 at 15:20
  • @csmith: It *is* perfectly valid to add a `Dog` to a `List`. I agree that C#'s generics is signficantly better, but the second part of your comment is off-base IMO. – Jon Skeet Oct 02 '16 at 15:51
27

Choosing the right type from the start is best, however to answer your question you can use type erasure.

return (ArrayList<MyInterface>) (ArrayList) myPojos;

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    IMO, this should be the answer, since in some cases, you simply can't add the items to a collection of the base type : think of JPA result set from queries, you got a list of JPA entities and if you like to return this list to the caller using some abstracting interface above the entity (persistence agnostic), Peter's advice is *the* way – Shmil The Cat Jun 24 '13 at 20:44
5

You should be doing:

public ArrayList<MyInterface> getMyInterfaces() {   
   ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);    
   myPojos.add(new MyPojo(0));    
   myPojos.add(new MyPojo(1));    
   return myPojos;
}
Jacob Schoen
  • 14,034
  • 15
  • 82
  • 102
0

In this case, I would do it like this:

public ArrayList<MyInterface> getMyInterfaces() {

    ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

MyPojo ist of type MyInterface (as it implements the interface). This means, you can just create the List with the Interface you need.

Tobias Langner
  • 10,634
  • 6
  • 46
  • 76
0

Try to use interfaces everywhere except when constructing instances, and you problems will go away:

public List<MyInterface> getMyInterfaces()
{
    List<MyInterface> myInterfaces = new ArrayList<MyInterface>(0);
    myInterfaces.add(new MyPojo(0));
    myInterfaces.add(new MyPojo(1));

    return myInterfaces;
}

As others have said already, the use of MyInterface fixes your problem. It is also better to use the List interface instead of ArrayList for return types and variables.

starblue
  • 55,348
  • 14
  • 97
  • 151
0

If myPojos has been declared as an ArrayList<MyPojo> you cannot just cast it to ArrayList<MyInterface> and return it. Peter Lawrey has shown how you can ignore the ominous screams of impending doom issued by the compiler when you try to do that, (I would add that his solution is missing a @SuppressWarnings( "unchecked" ) statement,) but it is still a very bad idea to do that.

That's because when you return an ArrayList<MyInterface> to the caller, then the caller can add an instance of SomeOtherPojo implements MyInterface into that ArrayList, resulting in your original ArrayList<MyPojo> containing a SomeOtherPojo among the MyPojos, which is a disastrous situation known as Heap Pollution (Wikipedia): attempting to iterate all the MyPojos in the original ArrayList<MyPojo> will throw a ClassCastException.

You might say that in your particular situation you know beyond a shadow of a doubt that none of this will happen, but this is programming by coincidence, and in any case the stackoverflow community has nothing to gain from answers that take into consideration the specifics of your particular situation. So, my advice to you would be to be courteous towards other programmers who might work with your code, follow the principle of least surprise, and do it properly.

You have two options:

  1. Create your ArrayList<MyInterface> and populate it as others have shown.
  2. Do not return an ArrayList<MyMyInterface>; instead, return a List<MyInterface> which has been created either with Collections.unmodifiableList( myPojos ) or (since Java 10) with List.copyOf( myPojos ). When a function returns a list, this list should be immutable. ArrayList is explicitly mutable, so it is unsuitable. Unfortunately, Java does not have an immutable list interface, but most people are accustomed to treating a List<E> returned by a function as immutable and never attempting to invoke any mutation methods on it. If they do, they will get a runtime error, which will be easy to fix, instead of the owner of myPojos receiving a completely inexplicable ClassCastException which is very hard to troubleshoot because it happens at an unknown point in time later.

For an explanation of what List.copyOf() does, and why it is a very good choice, see https://stackoverflow.com/a/72195980/773113

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142