简体   繁体   中英

How to return generic Collection from a function in Java?

So I can across this piece of code which is a demostration for generic methods in Java:

public static <T> T addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return element;
}

....

String stringElement = "stringElement";
List<String> stringList = new ArrayList<String>();
String theElement = addAndReturn(stringElement, stringList); 

But instead of returning the element I want to send back the whole collection object . I have tried few giving return type as Collection but it is somehow not working,

public static <T> Collection<T> addAndReturn(T element, Collection<T> collection) {
        collection.add(element);
        System.out.println(collection);
        return collection;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        // your code goes here
        String stringElement = "stringElement";
        List<String> strList = new ArrayList<String>();

        ArrayList<String> strRes = addAndReturn(stringElement, strList);
        System.out.println(strRes);
    }

and received this error:

Main.java:22: error: incompatible types: no instance(s) of type variable(s) T exist so that Collection conforms to ArrayList ArrayList strRes = addAndReturn(stringElement, strList); ^ where T is a type-variable: T extends Object declared in method addAndReturn(T,Collection) 1 error

can anyone help me with the solution ?

code sample is from Jenkov.com

Edit, given the comments from the OP: one has to understand that ArrayList derives from Collection. So when the interface of a method returns Collection<T> , then of course, you can only assign the result to a Collection , but not to a List/ArrayList. The fact that you pass in a List instance isn't known. The compiler only sees that a Collection comes back!

Coming back to the first question: your code is returning the element that got added:

public static <T> T addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return element;
}

Simply change the signature and the returned thing:

public static <T> Collection<T> addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return collection;
}

Done? Not really.

As in: that isn't good practice. Returning something that came in as parameter can quickly lead to confusion for readers of your code. Confusing your readers is a bad thing to do.

Beyond that: the whole method is simply bogus itself, as callers of the method could as well just write:

thatCollection.add(thatElement);

themselves. Your method doesn't add any value to the above! It rather obscures things for the readers.

Why would anybody want to write:

addAndReturn(someX, listOfXes);

instead of

listOfXes.add(someX);

If the point would be to do:

addAndReturn(someX, listOfXes).addAndReturn(someOtherX, listOfXes);

You rather go:

listOfXes.addAll(Arrays.asList(someX, someOtherX));

for example. Don't invent "utilities" for things that can be dealt with using standard library calls.

Is this what you are looking for?

public static <T> Collection<T> addAndReturn(T element, Collection<T> collection) {
    collection.add(element);
    return collection;
}

It goes like in the listing below.

public static <T> Collection<T> addAndReturn(final T element, final Collection<T> collection) {
    collection.add(element);
    return collection;
}

@Test
public void test() {
    final String stringElement = "stringElement";
    final List<String> stringList = new ArrayList<String>();
    final List<String> nextList = (List<String>) addAndReturn(stringElement, stringList);
    assertThat(nextList.get(0), is(equalTo(stringElement)));
}

All you have to care about is the right return parameter Collection<T> . Maybe you have to cast if you want it from a child class or interface like List final List<String> nextList = (List<String>) addAndReturn(stringElement, stringList); .

The error message is pointing to this line:

 ArrayList<String> strRes = addAndReturn(stringElement, strList); 

And it is telling you (in non-Compilerese plain English) that it could not find a generic type that would allow this assignment to happen.

Your method returns a Collection<T> (in this case a Collection<String> ). Collection<String> is not a subtype of ArrayList<String> , ergo, you are not allowed to assign an object of type Collection<String> to a field of type ArrayList<String> . Your method returns a Collection<String> , so the easiest fix is to just assign it to a field of type Collection<String> :

Collection<String> strRes = addAndReturn(stringElement, strList);

Alternatively, you could make use of local variable type inference (assuming you are using a current version of Java):

var strRes = addAndReturn(stringElement, strList);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM