Reputation: 976
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
Upvotes: 1
Views: 4771
Reputation: 369458
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);
Upvotes: 1
Reputation: 140427
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.
Upvotes: 7
Reputation: 379
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);
.
Upvotes: 1
Reputation: 5463
Is this what you are looking for?
public static <T> Collection<T> addAndReturn(T element, Collection<T> collection) {
collection.add(element);
return collection;
}
Upvotes: 1