Java generic method declaration [duplicate] - java

This question already has answers here:
What is the difference between bounded wildcard and type parameters?
(2 answers)
Closed 10 years ago.
I'm learning Java generics and I ask myself this question.
What is the difference between these two method declarations?
public static void someMethod(List<? extends Number> numberList);
and
public static <E extends Number> void someMethod(List<E> numberList);

In the latter you have a reference to the type within the scope of someMethod, namely E. In the former you do not.

The main difference is that the latter is a generic method the former is not.
So for example in the latter method you can do something like this:
public static <E extends MyObject> void someMethod(List<E> someList) {
E myObject = someList.iterator().next(); // this can actually lead to errors
myObject.doSomething(); // so treat it as an example
}
This means that you can substitute an arbitrary type E which conforms to the rule in the generic method declaration and be able to use that type in your method.
Be advised though that you should call the generic method with type arguments like this:
someClass.<MyArbitraryType>someMethod(someList);
You can find a nice overview of generic methods here.

With the second version you can do something like:
public static <E extends Number> void someMethod(List<E> numberList) {
E number = numberList.get(0);
numberList.add(number);
}
This isn't possible with the first version.

Using the first method declaration will not allow you to add anything new to the list. For example this will not compile.
public static void someMethod(List<? extends Number> numberList, Number number) {
numberList.add(number);
}
while the second allows you to do this:
public static <T extends Number> void someMethod(List<T> numberList, T number) {
numberList.add(number);
}

Related

Generics in java at method level [duplicate]

This question already has answers here:
Why does this Java method appear to have two return types?
(3 answers)
Closed 6 months ago.
I am new to java. I am trying to debug a code and not able to understand one line.
public interface CommandDispatcher {
<T extends BaseCommand> void registerHandler(Class<T> type, CommandHandlerMethod<T> handler);
void send(BaseCommand command);
}
I know generics but not able to understand below line.
<T extends BaseCommand> void registerHandler(Class<T> type, CommandHandlerMethod<T>)
what is <T extends BaseCommand> before void also I am not ablr to understand Class<T>
Can somebody explain me to understand the above line. Consider BaseCommand is an interface.
<T extends BaseCommand> means at the calling side Type T can be BaseCommand OR derived from BaseCommand class/interface.
Class<T> type means the first argument should be the type of Class T.
class Command extends BaseCommand{
}
then you can call like this
registerHandle( Command.class, ...);
So that inside implementation one can create instance of Type Command.

Generics in Java - Wildcard Usecases

We use wildcard in the method args when we want to pass list containing objects of child class. But as shown below we can achieve the same functionality using Type parameter. So why we need wildcards ?
Scenario
Lets say we have base-class named Department and its sub-classes named Development & Sales.
Development & Sales are subtypes of Department but List & List are not subtypes of List.
So when we want to pass list of Development or Sales object as method arg which is accepting list of any type of Department we use wildcard. But inside the code we can see we can achieve the same without using wildcard.
As per Effective Java using wildcard in return type is really a bad choice. What are the other usecases where wildcard is really helpful?
class MyGenericsClass<T extends SuperClass> {
//These 2 methods works the same
<H> void unboundedMethod1(AnotherGenericClass<H> arg) {
}
void unboundedMethod2(AnotherGenericClass<?> arg) {
}
//These two methods works the same
<H extends SuperClass> void boundedMethod1(AnotherGenericClass<H> arg) {
}
void boundedMethod2(AnotherGenericClass<? extends SuperClass> arg) {
}
//These two methods works the same
<U extends Building> void boundedListMethod1(List<U> list){
}
void boundedListMethod2(List<? extends Building> list) {
}
//Why can't we write like this? Giving Compile time error
//<U> void notWorkingMethod1(List<U extends SuperClass> list){ //Statements }
//<T> void notWorkingMethod2(List<U extends SuperClass> list){ //Statements }
}
Inside the notWorkingMethods1 and notWorkingMethods2 why can't we pass Bounded Type parameter directly but we can do so by first declaring it before return type ?
First, your initial assumption that the two methods behave the same is incorrect.
Assume the generic classes were Lists. Try adding something of type H to List<H> and anything to List<?> and see if they behave the same.
Regarding the last question.
<U extends Building> void boundedListMethod1(List<U> list)
Says that U is a type that extends Building and List contains that type.
However,
<U> void notWorkingMethod1(List<U extends Building> list)
Says that there is some type U and a List that expects a type U that extends Building. Those two statements do not imply compatibility. U may not be a subClass of Building but the List expects it.
WildCards are helpful when you just want to do something without regard to type.
List<Map<String,Integer>> list = ....
for (Map<?,?> m : list) {
System.out.println(m);
}
They are also useful for copying types.
public <H> void copy(List<? extends H> src, List<? super H> dst) {
for (H a : src) {
dst.add(a);
}
}

Java Generics: Type Extension In Method Declaration Parameters

I am learning Java Generics. My understanding is that Generics parameterize Collections by type. In the Oracle tutorial there is the following comment:
In generic code, the question mark (?), called the wildcard,
represents an unknown type.
On the next page there is the following example of method declaration with an upper-bounded wildcard in the parameters:
public void process(List<? extends Foo> list)
Given that, I am wondering why this method declaration is illegal:
public void process(List<E extends Number> list)
while this one is legal:
public <E extends Number> void process(List<E> list)
When specifying the method parm types, you're using the generic type, so it has to be defined upfront. In this statement, you use E without definition
public void process(List<E extends Number> list) { /* ... */ }
However, in the second one, it is defined before the method return type (void):
public <E extends Number> void process(List<E> list) { /* ... */ }
There's not a much better answer than "because that was how the language was designed." But one way of thinking about it is that type parameters are treated like another list of arguments to the method: they have to all appear at once, in one (ordered) list.
You can call generic methods by passing the type arguments explicitly: for example, foo.<Integer, String>process(list). That means that the type parameters have to have an explicit order, just like normal value arguments.
To complete on #phoenix's answer, the problem in this statement
public void process(List<E extends Number> list) { /* ... */ }
is that the declaration of your generic type E is in the wrong place. The right place is before the return type:
public <E extends Number> void process(List<E> list) { /* ... */ }
However, another possible place to define your generic type would be in the class declaration itself:
class MyClass<E extends Number> {
public void process(List<E> list) { /* ... */ }
}
Approximately both are same , but i am using first one only.

Java Generics insertion on wildcards

Java is not allowing me to add a subclass of the Type declaration in this class
public class Exam<T> {
public void set(Holder<? super T> hold){
}
public T get(Holder<? extends T> holder){ return holder.get();}
public static void main (String[] args){
Exam<Question> eq = new Exam<Question>();
eq.set(new Holder<Identification>());
}
}
Where Identification is a subclass of Question.
and this how my holder class looks like
public class Holder<T> {
T item;
public void set(T item){ this.item = item; }
public T get(){return item;}
}
ERROR
The method set(Holder<? super Question>) in the type Exam<Question> is not applicable for the arguments (Holder<Identification>)
The error looks pretty self-explanatory to me - the set method expects a Holder<? super Question> and you're trying to give it a Holder of something that is a subclass of Question. As written, Exam.set could take a Holder<Object>, for example, but not a Holder<Identification>.
A good way to think about extends and super in generics is in terms of assignment: T extends Foo will accept any type T that you could use on the right hand side of an assignment to Foo without casting, i.e.
Foo something = new T();
(treat this as pseudocode - I know you're not really allowed to new a type varaible). Conversely, T super Foo accepts any T you could use on the left hand side of an assignment without casting:
T myThing = new Foo();
In your specific example, Identification i = new Question() isn't legal without a cast, so a Holder<? super Question> parameter can't accept a Holder<Identification> value.
Exam<T> expects a Holder<T> that can hold any subclass of T. That's what the super does. You are passing a Holder<Identification> but Identification is neither T nor a superclass of it.
change set method of class Enum to
public void set(Holder<? extends T> hold){
}
Generic is invariant. That could be an answer for you. Invariant means that Type2 is a subclass of Type1 so it doesn't mean that List is a List.
It works (but has a different meaning, of course) if you write
public void set(Holder<? extends T> hold){ }

Java Generics Class Parameter Type Inference

Given the interface:
public interface BasedOnOther<T, U extends BasedList<T>> {
public T getOther();
public void staticStatisfied(final U list);
}
The BasedOnOther<T, U extends BasedList<T>> looks very ugly in my use-cases. It is because the T type parameter is already defined in the BasedList<T> part, so the "uglyness" comes from that T needs to be typed twice.
Problem: is it possible to let the Java compiler infer the generic T type from BasedList<T> in a generic class/interface definition?
Ultimately, I'd like to use the interface like:
class X implements BasedOnOther<Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
} // Does not compile, due to invalid parameter count.
Where Y extends BasedList<SomeType>.
Instead:
class X implements BasedOnOther<SomeType, Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
}
Where Y extends BasedList<SomeType>.
Update: ColinD suggested
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
It is impossible to create an implementation such as:
public class X implements BasedOnOther<SomeType> {
public SomeType getOther() { ... }
public void staticStatisfied(MemoryModel list);
} // Does not compile, as it does not implement the interface.
Where MemoryModel extends BasedList<SomeType>, which is needed (as it provides other methods).
It looks as if you don't actually need the type parameter U extends BasedList<T>, if you don't actually need to do anything in the class that requires some specific subclass/implementation of BasedList<T>. The interface could just be:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
Edit: Based on your update, I don't think there's any way you can do this. I think you'll have to either just go with your original declaration or make some intermediate type that specifies T, like:
public interface BasedOnSomeType<U extends BasedList<SomeType>>
extends BasedOnOther<SomeType, U>
{
}
public class X implements BasedOnSomeType<MemoryModel> { ... }
That seems like kind of a waste though, and I don't really think the original declaration looks that bad.
What about this?
public interface BasedOnOther<T> {
public T getOther();
public <U extends BasedList<T>> void staticStatisfied(final U list);
}
ColinD is almost correct. What you probably want is this:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<? extends T> list);
}
That's because method arguments are covariant but the generics are invariant. Look at this example:
public test() {
Number n1;
Integer n2; //Integer extends Number. Integer is a more-specific type of Number.
n1 = n2; //no problem
n2 = n1; //Type mismatch because the cast might fail.
List<Number> l1;
List<Integer> l2;
List<? extends Number> l3;
l1 = l3; //No problem.
l1 = l2; //Type mismatch because the cast might fail.
}
Why:
Trying to put an Integer where a Number belongs is covariance and it's usually correct for function arguments.
Trying to put a Number where an Integer belongs is the opposite, contravariance, and it's usually correct for function return values. For example, if you defined a function to return a Number, it could return an Integer. If you defined it to return an Integer, however, you couldn't return a Number because that might be a floating-point, for example.
When you're dealing with generics, the compiler can't tell if the generic parameter (in your case, T) is going to be covariant or contravariant. In your code, for example, T is once a return value and once part of an argument. For that reason, generic parameters are invariant by default.
If you want covariance, use <? extends T>. For contravariance, use <? super T>. As a rule of thumb, you probably always want to specify the covariance/contravariance on all public functions. For private functions it doesn't matter as much because you usually already know the types.
This isn't specific to java, other object-oreiented languages have similar issue.
I recently had a very similar problem.
I would suggest, if you are do not need to specifically refer to MemoryModel, i.e. if U extends BasedList<T> is enough, then I would definitely do what Pepe answered.
However, if you must type check for at least two methods that both methods must use MemoryModel specifically and the type inferencing in Pepe's answer is not enough, then the only way to make the use of the clumsy/verbose parameterized constructor more simplistic, is to exploit the generic method parameter inferencing. You would need to create generic static factory methods for each constructor, where the factory methods do the type inferencing (constructors can't type inference in Java).
How to do this is covered in
Effective Java, by Joshua Block; Item 27: Favor generic methods
I also explained this and quoted the solution (with code) here.

Categories

Resources