Search code examples
javaarraylistlinked-listgeneric-programming

When returning an ArrayList do I have to return the <Type> along with it?


Specifically, if I return a filled ArrayList do I have to return the type with it such as ArrayList<modNode>? To add onto this, if i'm using a generic typing for a custom link list that uses the <T> tag would I have to return ArrayList<modNode<T>>? Just a little curious on the properties of ArrayLists containing generic objects... Thanks in advance!


Solution

  • Let's say you have a method that returns an ArrayList of String objects:

    public ArrayList<String> foo() {
        ArrayList<String> list = new ArrayList<>();
        // ... fill list ...
        return list;
    }
    

    This is how you would normally1 declare the method in Java 5+ (since the addition of generics). But you don't have to do this. You could declare the method as:

    public ArrayList foo() {
        // ... code ...
        return list;
    }
    

    This would mean you are using raw types. Unless you are interacting with a legacy (pre Java 5) library/application you never want to use raw types. The reason is because a raw type is (nearly?) equivalent to returning ArrayList<Object>. You've just lost all type safety given by generics. The reason for generics is to provide compile-time2 type checks so you don't accidentally use the wrong types. For instance, you could now add a Dog to the ArrayList returned by foo even though you intended it to only contain String objects. Also, code using the returned ArrayList has no guarantee that there will only be String objects inside the ArrayList which can result in all sorts of headaches.

    You could get around raw types by casting:

    String element = (String) foo().get(0);
    

    However, that's basically what generic code compiles down to anyway; except you no longer have compile-time safety.

    If the element type is also generic then yes you would want to return that information as well. Let's say you return an ArrayList of Supplier objects instead. It will be each Supplier that returns the needed String objects.

    public ArrayList<Supplier<String>> foo() {
        // ... code ...
    }
    

    It's important you give the Supplier's generic signature here so you can do things like:

    for (Supplier<String> sup : foo()) {
        String str = sup.get();
        // .. do something with "str" ...
    }
    

    If you returned ArrayList<Supplier> then each Supplier.get() would return an Object. You've lost all type safety again.


    1. You would actually, in virtually all cases, want to return List rather than ArrayList. It's best to program to an interface.

    2. It only works at compile-time due to type erasure. Also see this.