Java Generics at method level - java

Can anyone please explain me below code
public <T extends Emp> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
I am trying to understand how Generics will apply on void return type.
Note: i have changed the code now it is not giving any error.

I am trying to understand how generics will apply on void return type.
This is only a syntax. Generics do not apply to void return type, they apply to the method as a whole.
The name and restrictions on the generic parameter need to go somewhere in the text of your program. In a class declaration they follow the class name in angular brackets. In a generic method declaration they follow the accessibility designator public, and precedes the return type void.
One could easily imagine an alternative placement of generic types, such as
public void foo<T extends Emp>(ArrayList<T> list) // Imaginary syntax
or even
public void foo(ArrayList<T> list) <T extends Emp> // Imaginary syntax
but Java designers decided on the placement before the return type designator.

Generics won't be applied to void.
If you say that the type is <T extends Emp>, you are saying, that any subtype of Emp can be applied in place of T.
In your code, You can use <T> instead of <T extends Emp> as you aren't doing anything with Emp
public <T> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
Regarding how it'll work, the type will be provided by you when you use this method and at compile time, java will place required casts automatically. So, if you are using this:
ArrayList<String> list = new ArrayList<>();
// Add some items into list
foo(list);
in that case, your foo() method will find out that type <T> is String and so, will behave something like:
public void foo(ArrayList<String> list) {
list.add((String)(list.remove(0)));
}

Related

Wildcard vs TypeParameter

class Employee<T extends Number> { // valid
}
class Employee<? extends Number> { // invalid
}
private static void test(List<? super Number> list1) { // valid
}
private static <T>void test(List<T super Number> list1) { // invalid
}
what exactly is difference between ? and T and when to use what?
Why with class definition, ? doesn't work but it works with List and why T works with class definition but not with List?
Where to declare a generic
You can not use a generic type token T before introducing it.
In your method example you try to declare the T at the wrong spot, that is invalid syntax. You have to introduce it beforehand.
For the class example however, you have put it in the right spot.
Here is where you can introduce your generic type token on a class wide level:
public class Foo< HERE > { ... }
and thats how you do it for a method only:
public < HERE > void foo(...) { ... }
Bounded generics
In both cases you can bound your T, like T extends Number and then use it accordingly:
public class Foo<T extends Number> { ... }
// or
public <T extends Number> void foo(...) { ... }
After you have introduced your T, you will use it just like that. So List<T>, as an example.
public <T extends Number> void foo(List<T> list) { ... }
Note that T super Number is invalid on as it makes little sense and does not provide more information than just T or Number or simply Object, depending on what you are trying to achieve. You can read more about that at Java generic methods: super can't be used?
Wildcards
Wildcards are a different thing. They are not a generic type token that you have to introduce first, such as T. Instead, they clarify the type range you want to accept.
For example a method like
public static void foo(List<? super Dog> list) { ... }
can be called with a List<Dog>, a List<Animal> or even a List<Object>. We call such a list a consumer of Dogs. To be precise, these are all lists that would accept a dog, so list.add(new Dog()) will work.
On the other side, we have
public static void foo(List<? extends Dog> list) { ... }
which can be called with a List<Dog> or also a List<Chihuahua>. We call such a list a producer (or provider) of Dogs. To be precise, these are all lists that can provide dogs. So Dog dog = list.get(0) will work.
You can read more about the details of what wildcards are and how they work at What is PECS (Producer Extends Consumer Super)?
When to use which?
In general, you would use a generic type token T when you actually still need to maintain the type safety throughout your code. I.e. when you need to be able to give the type a name. Otherwise you use wildcards ?.
For example, suppose you want to create a method that takes in a list and an element to add to it:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
You need to introduce the T to ensure that the type of the list matches the given element. Otherwise someone could do addToList(dogs, cat), which you do not want.
If you do not have the need to actually name the type, you can also just use a wildcard. For example a method that takes a list and prints all its contents:
public static void printAll(List<?> list) {
for (Object object : list) {
System.out.println(object);
}
}

Add generic value to a map in generic method in java

I'm not that familiar with java Generics (using IntelliJ).
What I want is adding generic values to collections.
Two question for the code below.
I read https://docs.oracle.com/javase/tutorial/java/generics/methods.html
and https://docs.oracle.com/javase/tutorial/extra/generics/methods.html
but don't know why the code below has an error.
Q1) I have error message in map.put(T, T); in add method such that red ripple under Ts: Expression Expected, introduce local variable
Q2) Wondering in this case, should I declare class as public class Test<T> or can I declare public class Test?
public class Test<T> {
Map<T, T> map;
public Test() {
map = new HashMap<T, T>();
}
public <T> void add(T value) throws Exception {
map.put(value, value); // Q1) red ripple under value: Expression Expected, introduce local variable
}
}
There are two problems in here.
The generic method parameter T hides the class one T. They are different types and you have no ways to refer to that T (unless you rename one of them).
The method map.put expects values of T type, not this type itself (it is not an instance of Class anyway).
The solution:
public void add(T value) throws Exception {
map.put(value, value);
}
Wondering in this case, should I declare class as public class Test<T> or can I declare public class Test?
You don't necessarily need to declare class generic types if you want few generic methods - make your methods with their own generic types. Note that there won't be any resemblance between them.
But, in your case, a generic type T is mandatory since you declared a generic field Map<T, T> map.

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 generic programming with unknown generic type of interface

I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.

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