Java Generics - List<?> vs List<T> - java

Consider the following 2 alternate APIs:
void method(List<?> list)
<T> void method(List<T> list)
I know that their internal implementation will have many differences to deal with, such as List<?> wont be able to write into the list etc.
Also, in my knowledge List<?> will allow any parameterized type with List as base type. So will be the case with List<T> also.
Can anybody tell me if there is any difference at all in what kinds of inputs these 2 APIs will accept. (NOT the 2 APIs internal implementation differences.)

The internal implementation is exactly the same. In fact, both methods compiled with javac will yield equal method byte code, if they compile at all).
However, during compilation, the first method is specified to not care about the component type of the list, while the second requires that the component type be invariant. This means that whenever I call such a method, the component type of list will be fixed by whatever the call site uses.
I can call my method with a List<String> and T will be synonymous to String during the call (from the perspective of the compiler). I can also call it with a List<Runnable> and T will be synonymous to Runnable during the call.
Note that your method does not return anything, but it very well could do so depending on the arguments. Consider the method:
<T> T findFirst(Collection<T> ts, Predicate<T> p) { … }
You can use this method for each T. BUT it only works if our T is equal for the collection and predicate — this is what "invariance" means. You could in fact specify the method to be applicable in more contexts:
<T> T findFirst(Collection<? extends T> ts, Predicate<? super T> p) { … }
This method would work the same as above, but it would be more lenient in what types it accepts. Consider a type hierarchy A extends B extends C. Then you could call:
Collection<A> cs = …;
Predicate<C> p = …;
B b = findFirst(cs, p);
We call the type of ts covariant and the type of p (in the method signature) contravariant.
Wildcards (?) are a different matter. They can be bounded (like in our cases above) to be co- or contravariant. If they are unbounded, the compiler actually needs a concrete type to fill in at compile time (which is why you will sometimes get errors like "type wildcard-#15 is not a match for wildcard-#17"). The specific rules are laid out in the Java Language Specification, Section 4.5.1.

Related

Return ChildClass.class pointer in method which returns Class<T extends BaseClass>

I have a method that is supposed to analyze a String and determine the correct Class<T>, where T extends BaseClass.
Suppose that BaseClass is extended by Child1, Child2 and Child3.
In my method, I want to do something like this:
public <T extends BaseClass> Class<T> from(String number) {
if (number.contains("Child1")) {
return Child1.class;
} else if (number.contains("Child2")) {
return Child2.class;
} else if (number.contains("Child3")) {
return Child3.class;
}
throw new UnsupportedOperationException("Cannot recognize class from " + number);
}
The problem is that the above method doesn't compile on all return statements, because Required type is Class<T>, provided is Class<Child1> (same for Child2 and Child3 of course).
Hence, I am forced to (unchecked) cast:
return (Class<T>) Child1.class;
... which of course works fine, since Child1.class is compatible with Class<T>.
How can I do what I'm trying to do in a cleaner way (without having the warning)?
... which of course works fine, since Child1.class is compatible with Class<T>.
That's incorrect. Understandable, as you're making a common mistake.
The fix
The fix is to have the return type be Class<? extends T> instead. But, scratch that...
But this code is bad style
Generics serve to link things. Any type variable should therefore be declared once and used in at least 2 places, or it is one of:
useless.
actively misleading.
a type-safety breaking hack.
I assume you intended none of that. You have declared T once, and are using it once, which therefore means it's incorrect. The correct version is:
public Class<? extends BaseClass> from(String number) { ... }
This does everything you want. Specifically, something like this:
BaseClass bc = from("Child3").getConstructor().newInstance();
will just compile, no need for casts (you will need to festoon this up with rather a lot of try/catch, but no need for a cast, at least), and the compiler will not emit type safety warnings either. Which, presumably, is what you're trying to accomplish.
Explanation
In java, typing relationships are covariant. That means any type can stand in for any of its supertypes.
In other words:
Number n = Integer.valueOf(5);
is valid java.
But the thing that generics are for simply doesn't adhere to this rule. Here is a trivial example. Imagine generics was just as covariant as basic type usage in java would be. Then I could write this, it would compile, and that would be bad, because this code would then be breaking the typing system:
List<Integer> listOfInts = List.of(1, 2, 3);
List<Number> listOfNums = listOfInts;
listOfNums.add(Double.valueOf(5.5));
int value = listOfInts.get(3);
Go through the above code and you realize there's a fundamental issue here.
The fix is that generics are invariant - a type is a valid standin only for itself; not for anything else.
In other words, the one and only thing you can assign to a List<Number> is an expression of type List<Number> or perhaps ArrayList<Number> ( because the non-generics part is covariant, we're talking only about the stuff in the <>), not List<Integer>.
That's the fix - that's why the above code isn't actually a problem for the typing system in java - it simply won't compile.
Now, when there is no such thing as 'adding', this becomes dubious, and Class is just such a type: Yes it's got a type param but you can't 'break stuff' if generics was covariant. Unfortunately, the generics feature of java does not ship with a gigantic list of 'the generics on THIS type can be covariant, but here they cannot be'.
Instead, java lets you choose your variance, and the APIs change to reflect what that means:
List<? extends Number> list = someListOfIntegers; // co-variance
List<? super Number> list = someListOfObject; // contra-variance
List list = someListOfAnything; // legacy-variance a.k.a. raw
List<Number> list = someListOfNumber; // invariance
Of course, you don't get this stuff for free: That covariant list (List<? extends Number>), you cannot call add on this list, at all. Well, the literal .add(null), because null is a standin for all types, that works, but nothing else will, add is always a compile time error. That's the cost. If you opt out of all add methods on a list, then and only then can you write a method that accepts as parameter a list of numbers, or integers, or doubles, etc.
With Class it gets dubious (as there's no 'writing'), but the co/contra/invariant system is baked into generics and doesn't care about the fact that Class doesn't have any add-style methods in it.

Java 8 type inference cause to omit generic type on invocation

I have a Problem with a generic method after upgrading to Java 1.8, which was fine with Java 1.6 and 1.7
Consider the following code:
public class ExtraSortList<E> extends ArrayList<E> {
ExtraSortList(E... elements) {
super(Arrays.asList(elements));
}
public List<E> sortedCopy(Comparator<? super E> c) {
List<E> sorted = new ArrayList<E>(this);
Collections.sort(sorted, c);
return sorted;
}
public static void main(String[] args) {
ExtraSortList<String> stringList = new ExtraSortList<>("foo", "bar");
Comparator<? super String> compGen = null;
String firstGen = stringList.sortedCopy(compGen).get(0); // works fine
Comparator compRaw = null;
String firstRaw = stringList.sortedCopy(compRaw).get(0); // compiler ERROR: Type mismatch: cannot convert from Object to String
}
}
I tried this with the Oracle javac (1.8.0_92) and with Eclipse JDT (4.6.1) compiler. It is the same result for both. (the error message is a bit different, but essentially the same)
Beside the fact, that it is possible to prevent the error by avoiding raw types, it puzzles me, because i don't understand the reason.
Why does the raw method parameter of the sortedCopy-Method have any effect on the generic type of the return value? The generic type is already defined at class level. The method does not define a seperate generic type. The reference list is typed to <String>, so should the returned List.
Why does Java 8 discard the generic type from the class on the return value?
EDIT: If the method signature of sortedCopy is changed (as pointed out by biziclop) to
public List<E> sortedCopy(Comparator c) {
then the compiler does consider the generic type E from the type ExtraSortList<E> and no error appears. But now the parameter c is a raw type and thus the compiler cannot validate the generic type of the provided Comparator.
EDIT: I did some review of the Java Language Specification and now i think about, whether i have a lack of understanding or this is a flaw in the compiler. Because:
Scope of a Declaration of the generic type E is the class ExtraSortList, this includes the method sortedCopy.
The method sortedCopy itself does not declare a generic type variable, it just refers to the type variable E from the class scope. see Generic Methods in the JLS
The JLS also states in the same section
Type arguments may not need to be provided explicitly when a generic method is invoked, as they can often be inferred (§18 (Type Inference)).
The reference stringList is defined with String, thus the compiler does not need to infer a type forE on the invocation of sortedCopy because it is already defined.
Because stringList already has a reified type for E, the parameter c should be Comparator<? super String> for the given invocation.
The return type should also use the already reified type E, thus it should be List<String>.
This is my current understanding of how i think the Java compiler should evaluate the invocation. If i am wrong, an explanation why my assumptions are wrong would be nice.
To bring an final answer to why this happens:
Like #Jesper mentioned already, you're using raw types when you shouldn't (Especially when using the Generic as type in multiple cases).
Since you pass an Comparator without an Generic-Type, there will actually be none. You could think of the E-Generic as null to make it easier. Therefore your code becomes to this:
public List sortedCopy(Comparator c) {
List sorted = new ArrayList(this);
Collections.sort(sorted, c);
return sorted;
}
Now you're attemptig/assuming you get an String from an List without Generics and therefore an Object (hence it's the super-class of everything ).
To the question why the raw-type parameter has no effect on the return type, since you don't specify an certain Level of abstraction. You'd have to define an Type that the Generic has to extend/implement at least to make that happen (compilation errors), for example.
public class ExtraSortList<E extends String> extends ArrayList<E> {
will now only allow Strings or Classes which extend it (not possible here since string is final). With that, your fallback Type would be String.

Which of the overloaded methods will be called on runtime if we apply type erasure, and why?

Suppose we have the following generic class
public class SomeType<T> {
public <E> void test(Collection<E> collection){
System.out.println("1st method");
for (E e : collection){
System.out.println(e);
}
}
public void test(List<Integer> integerList){
System.out.println("2nd method");
for (Integer integer : integerList){
System.out.println(integer);
}
}
}
Now inside main method we have the following code snippet
SomeType someType = new SomeType();
List<String> list = Arrays.asList("value");
someType.test(list);
As a result of executing someType.test(list) we will get "2nd method" in our console as well as java.lang.ClassCastException. As I understand, the reason of why second test method being executed is that we don't use generics for SomeType. So, compiler instantly removes all generics information from the class (i.e. both <T> and <E>). After doing that second test method will have List integerList as a parameter and of course List matches better to List than to Collection.
Now consider that inside main method we have the following code snippet
SomeType<?> someType = new SomeType<>();
List<String> list = Arrays.asList("value");
someType.test(list);
In this case we will get "1st method" in the console. It means that first test method being executed. The question is why?
From my understanding on runtime we never have any generics information because of type erasure. So, why then second test method cannot be executed. For me second test method should be (on runtime) in the following form public void test(List<Integer> integerList){...} Isn't it?
Applicable methods are matched before type erasure (see JSL 15.12.2.3). (Erasure means that runtime types are not parameterized, but the method was chosen at compile time, when type parameters were available)
The type of list is List<String>, therefore:
test(Collection<E>) is applicable, because List<Integer> is compatible with Collection<E>, where E is Integer (formally, the constraint formula List<Integer> → Collection<E> [E:=Integer] reduces to true, because List<Integer> is a subtype of Collection<Integer>).
test(List<String>) is not applicable, because List<String> is not compatible with List<Integer> (formally, the constraint formula List<String> → List<Integer> reduces to false because String is not a supertype of Integer).
The details are explained hidden in JSL 18.5.1.
For test(Collection<E>):
Let θ be the substitution [E:=Integer]
[...]
A set of constraint formulas, C, is constructed as follows: let F1, ..., Fn be the formal parameter types of m, and let e1, ..., ek be the actual argument expressions of the invocation.
In this case, we have F1 = Collection<E> and e1 = List<Integer>
Then: [the set of constraint formulas] includes ‹ei → Fi θ›
In this case, we have List<Integer> → Collection<E> [E:=Integer] (where → means that e1 is compatible with F1 after the type-variable E has been inferred)
For test(List<String>), there is no substitution (because there are no inference variables) and the constraint is just List<String> → List<Integer>.
The JLS is a bit of a rat's nest on this one, but there is an informal (their words, not mine) rule that you can use:
[O]ne method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
For the sake of argument, let's call <E> test(Collection<E>) method 1, and test(List<Integer>) method 2.
Let's throw a spanner in here - we know that this entire class is generic, so instantiation of it without a type of some kind produces... less than desirable type checks at runtime.
The other part to this is due to the fact that List is more specific than Collection, if a method is passed a List, it will seek to accommodate that more readily than a Collection, with the caveat that the type should be checked at compile time. Since it isn't with that raw type, I believe that this particular check is skipped, and Java is treating List<Integer> as more specific than Collection<capture(String)>.
You should file a bug with the JVM, since this appears to be inconsistent. Or, at least, have the folks who penned the JLS explain why this is legal in slightly better English than their wonky math notation...
Moving on; with your second example, you give us the courtesy of typing your instance as a wildcard, which allows Java to make the correct compile-time assertion that test(Collection<E>) is the safest method to choose.
Note that none of these checks happen at runtime. These are all decisions made before Java runs, as ambiguous method calls or a call to a method with an unsupported parameter results in a compile time error.
Moral of the story: don't use raw types. They're evil. It makes the type system behave in strange ways, and it's really only there to maintain backwards compatibility.

Difference between List<T> and List<? extends T> [duplicate]

Given the following example (using JUnit with Hamcrest matchers):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
This does not compile with the JUnit assertThat method signature of:
public static <T> void assertThat(T actual, Matcher<T> matcher)
The compiler error message is:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
However, if I change the assertThat method signature to:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Then the compilation works.
So three questions:
Why exactly doesn't the current version compile? Although I vaguely understand the covariance issues here, I certainly couldn't explain it if I had to.
Is there any downside in changing the assertThat method to Matcher<? extends T>? Are there other cases that would break if you did that?
Is there any point to the genericizing of the assertThat method in JUnit? The Matcher class doesn't seem to require it, since JUnit calls the matches method, which is not typed with any generic, and just looks like an attempt to force a type safety which doesn't do anything, as the Matcher will just not in fact match, and the test will fail regardless. No unsafe operations involved (or so it seems).
For reference, here is the JUnit implementation of assertThat:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
First - I have to direct you to http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html -- she does an amazing job.
The basic idea is that you use
<T extends SomeClass>
when the actual parameter can be SomeClass or any subtype of it.
In your example,
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
You're saying that expected can contain Class objects that represent any class that implements Serializable. Your result map says it can only hold Date class objects.
When you pass in result, you're setting T to exactly Map of String to Date class objects, which doesn't match Map of String to anything that's Serializable.
One thing to check -- are you sure you want Class<Date> and not Date? A map of String to Class<Date> doesn't sound terribly useful in general (all it can hold is Date.class as values rather than instances of Date)
As for genericizing assertThat, the idea is that the method can ensure that a Matcher that fits the result type is passed in.
Thanks to everyone who answered the question, it really helped clarify things for me. In the end Scott Stanchfield's answer got the closest to how I ended up understanding it, but since I didn't understand him when he first wrote it, I am trying to restate the problem so that hopefully someone else will benefit.
I'm going to restate the question in terms of List, since it has only one generic parameter and that will make it easier to understand.
The purpose of the parametrized class (such as List<Date> or Map<K, V> as in the example) is to force a downcast and to have the compiler guarantee that this is safe (no runtime exceptions).
Consider the case of List. The essence of my question is why a method that takes a type T and a List won't accept a List of something further down the chain of inheritance than T. Consider this contrived example:
List<java.util.Date> dateList = new ArrayList<java.util.Date>();
Serializable s = new String();
addGeneric(s, dateList);
....
private <T> void addGeneric(T element, List<T> list) {
list.add(element);
}
This will not compile, because the list parameter is a list of dates, not a list of strings. Generics would not be very useful if this did compile.
The same thing applies to a Map<String, Class<? extends Serializable>> It is not the same thing as a Map<String, Class<java.util.Date>>. They are not covariant, so if I wanted to take a value from the map containing date classes and put it into the map containing serializable elements, that is fine, but a method signature that says:
private <T> void genericAdd(T value, List<T> list)
Wants to be able to do both:
T x = list.get(0);
and
list.add(value);
In this case, even though the junit method doesn't actually care about these things, the method signature requires the covariance, which it is not getting, therefore it does not compile.
On the second question,
Matcher<? extends T>
Would have the downside of really accepting anything when T is an Object, which is not the APIs intent. The intent is to statically ensure that the matcher matches the actual object, and there is no way to exclude Object from that calculation.
The answer to the third question is that nothing would be lost, in terms of unchecked functionality (there would be no unsafe typecasting within the JUnit API if this method was not genericized), but they are trying to accomplish something else - statically ensure that the two parameters are likely to match.
EDIT (after further contemplation and experience):
One of the big issues with the assertThat method signature is attempts to equate a variable T with a generic parameter of T. That doesn't work, because they are not covariant. So for example you may have a T which is a List<String> but then pass a match that the compiler works out to Matcher<ArrayList<T>>. Now if it wasn't a type parameter, things would be fine, because List and ArrayList are covariant, but since Generics, as far as the compiler is concerned require ArrayList, it can't tolerate a List for reasons that I hope are clear from the above.
It boils down to:
Class<? extends Serializable> c1 = null;
Class<java.util.Date> d1 = null;
c1 = d1; // compiles
d1 = c1; // wont compile - would require cast to Date
You can see the Class reference c1 could contain a Long instance (since the underlying object at a given time could have been List<Long>), but obviously cannot be cast to a Date since there is no guarantee that the "unknown" class was Date. It is not typsesafe, so the compiler disallows it.
However, if we introduce some other object, say List (in your example this object is Matcher), then the following becomes true:
List<Class<? extends Serializable>> l1 = null;
List<Class<java.util.Date>> l2 = null;
l1 = l2; // wont compile
l2 = l1; // wont compile
...However, if the type of the List becomes ? extends T instead of T....
List<? extends Class<? extends Serializable>> l1 = null;
List<? extends Class<java.util.Date>> l2 = null;
l1 = l2; // compiles
l2 = l1; // won't compile
I think by changing Matcher<T> to Matcher<? extends T>, you are basically introducing the scenario similar to assigning l1 = l2;
It's still very confusing having nested wildcards, but hopefully that makes sense as to why it helps to understand generics by looking at how you can assign generic references to each other. It's also further confusing since the compiler is inferring the type of T when you make the function call (you are not explicitly telling it was T is).
The reason your original code doesn't compile is that <? extends Serializable> does not mean, "any class that extends Serializable," but "some unknown but specific class that extends Serializable."
For example, given the code as written, it is perfectly valid to assign new TreeMap<String, Long.class>() to expected. If the compiler allowed the code to compile, the assertThat() would presumably break because it would expect Date objects instead of the Long objects it finds in the map.
One way for me to understand wildcards is to think that the wildcard isn't specifying the type of the possible objects that given generic reference can "have", but the type of other generic references that it is is compatible with (this may sound confusing...) As such, the first answer is very misleading in it's wording.
In other words, List<? extends Serializable> means you can assign that reference to other Lists where the type is some unknown type which is or a subclass of Serializable. DO NOT think of it in terms of A SINGLE LIST being able to hold subclasses of Serializable (because that is incorrect semantics and leads to a misunderstanding of Generics).
I know this is an old question but I want to share an example that I think explains bounded wildcards pretty well. java.util.Collections offers this method:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
If we have a List of T, the List can, of course, contain instances of types that extend T. If the List contains Animals, the List can contain both Dogs and Cats (both Animals). Dogs have a property "woofVolume" and Cats have a property "meowVolume." While we might like to sort based upon these properties particular to subclasses of T, how can we expect this method to do that? A limitation of Comparator is that it can compare only two things of only one type (T). So, requiring simply a Comparator<T> would make this method usable. But, the creator of this method recognized that if something is a T, then it is also an instance of the superclasses of T. Therefore, he allows us to use a Comparator of T or any superclass of T, i.e. ? super T.
what if you use
Map<String, ? extends Class<? extends Serializable>> expected = null;

When is it acceptable to pass a Class<T> argument to a generic method?

Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?

Categories

Resources