generic method write to a list - java

I am trying to create a generic method which accepts a list of numbers in the format below. I know that I should be able to add any class to the list "o" which is at least a number (floats, integers, doubles) BUT also I should be able to add any object because all classes extend from object. In other words, object is a super class of any classs. So I wonder, why do I get an error on the line o.add(p); ?
public int checkType(List<? super Number> o)
{
Object p = new Object();
//error
o.add(p);
return - 1;
}
I followed the explanation of generics from Difference between <? super T> and <? extends T> in Java which is the accepted answer.

The type-parameter List<? super Number> o specifies that any List which can hold a Number can be passed to it.
Which could be List<Object>, but that could also be List<Number>.
So compiler will allow you to add only Number (or subtype) objects to it.
To test, call your methods with the following arguments.
checkType(new ArrayList<Object>()); // Works fine (and it can hold Object type).
checkType(new ArrayList<Number>()); // Works fine (But it can NOT hold Object type).
So, as you see a List<? super Number> means that you are trying to add a Number to the list (Rule of PECS).

One consideration?
List<Object> myObjectList = Arrays.asList(1, 2, new SuperObject(), 4, 5);
Java comes standard with a utility class Arrays.

Related

why a function like this idGetter can not be applied to Map function in java stream api?

public <T> List<Long> leafIds(Map<Long, ? extends List<? extends T>> childrenMap, Long parentId, Function<? extends T, Long> idGetter) {
if (!childrenMap.containsKey(parentId)) {
return Collections.singletonList(parentId);
}
List<Long> result = new ArrayList<>();
List<Long> childrenIds = new ArrayList<>();
childrenIds.add(parentId);
for (int i = 0; i < childrenIds.size(); i++) {
Long childId = childrenIds.get(i);
List<? extends T> children = childrenMap.get(childId);
if (CollectionUtils.isNotEmpty(children)) {
childrenIds.addAll(children.stream().filter(Objects::nonNull).map(idGetter).collect(Collectors.toList()));
continue;
}
result.add(childId);
}
return result;
}
error mark
there is an error mark under line 12, the editor indicates that type of [idGetter] is wrong,how can I fix this?
I'll be grateful for any help!
Function<? extends T, Long> means:
Any function that converts some specific but unknown thing to a Long, where we do know that, whatever it is, it's either T or some subtype thereof.
It specifically does not mean: "A function that can take any T and convert it to a Long". If you want that, you'd need a Function<T, Long>.
List<? extends T> means:
A list whose elements are constrained; they must all be instanceof some type we don't know. We do know that, whatever type it is, it is at least T or some subtype of T.
It specifically does not mean: A list whose elements are constrained to be instanceof T. Because that'd just be a List<T>.
The expression list.get(0), if list is a List<T>, is itself T. Obviously. It's still T if the list is a List<? extends T> instead. The crucial difference is with add: you can call list.add(someInstanceOfT) just fine, if the type of list is List<T>. However, list.add(anything) doesn't compile if list's type is List<? extends T>.
Think about it:
List<Integer> myList = new ArrayList<Integer>();
List<? extends Number> numbers = myList;
numbers.add(someDouble);
The above does not compile - specifically, the third line (numbers.add) does not. And now it should be obvious why: The numbers variable is pointing at a list whose constraint is unknown. Maybe it is Integer, which would mean adding a double to it, is broken.
The key thing to keep in mind is PECS: Produce-Extends-Consume-Super. This is from the point of view of the object: a list.get() call "produces" a value, therefore, extends bounds are useful (a List<? extends Number> can be used for meaningful production, because PE: Produce-Extends: .get() call, which produces, gives you Number. Or flip it around, CS: a List<? super Number> can meaningfully consume: list.add(someNumber) is allowed on them. But list.get(0) on a List<? super Number> is not particularly useful (it gets you an object, because all lists can't store anything else, but nothing more specific).
Now back to functions. The first typearg of a function is solely used for consumption: The point of that first arg is that your function consumes these. The second argument is solely used for production.
Thinking about PECS, Function<? extends Anything, _> is completely useless, given that extends means its useful only for production, and the first typearg of Function is solely used for consumption.
Java is 'correct', your code is broken. What did you really mean?
Two options:
Option 1
If you intend to accept a function that can process any T, then it should be either a Function<T or a Function<? super T, as per PECS rules.
Option 2
Generics serve to link things, given that they are a figment of the compiler's imagination (java the VM doesn't know what they are, and most of the type args are erased entirely by javac). Perhaps you intended to link the type used in the first parameter with the type used in that function. Then.. make a type variable for that purpose, that is their job. You've already done that, so, fix up your bounds so they align with PECS:
public <T> List<Long> leafIds(Map<Long, ? extends List<? extends T>> childrenMap, Long parentId, Function<? super T, Long> idGetter) {
All I did was swap ? extends to ? super. What that says is:
There is some specific type. No idea what it is, though. Let's call it T.
The first argument gives us a map that maps to a list of Xs, where X is either that unknown type T or some subtype of that.
The third argument is a mapping function that is capable of converting some unknown type to something else. The unknown type it can convert is, however, guaranteed to be either T or some supertype of it.
That paints a complete, type-wise consistent picture. Let's say the map gives out Integers and the function can convert any Object (so, T is Number, the list are a subtype of T: Integer, check, and the mapping function can convert any Object, that's a supertype of T, so, check). That works out.
Now let's go in reverse:
The lists have Numbers in them, and the mapping function can only convert Doubles.
So what happens if one of the elements in the list is an Integer instead? Type safety broken.

Usuage of ? extends anyobject in Java Generics

List<? extends Number> l = new ArrayList<Integer>();
I have the above line of code.
The object 'l' can refer any objects which can be Number any of its sub types.
I know that we can not add anyting to the above list.
Then what is the use of "? extends any_object" since we can not add anything to it ?
In what kind of context it is used ?
Can anyone please explain.
Thanks!!
It’s most useful for method arguments. Consider this:
public void printFormatted(Collection<? extends Number> values) {
NumberFormat format = new DecimalFormat("0.000");
for (Number value : values) {
System.out.println(format.format(value));
}
}
If I declare the method with Collection<Number>, callers must pass a Collection (or List or Set) whose generic type is known to be Number. They cannot pass Collection<Integer>, because Collection<Integer> is not a subclass of Collection<Number> and in fact is not polymorphically compatible with Collection<Number>.
By declaring the method with Collection<? extends Number>, I am saying that callers can pass Collection<Number>, or Collection<Integer>, or Collection<Double>, etc. List<Integer> or Set<Integer> is also acceptable, since the class is polymorphic, even though the generic type is not.
One of possible examples:
When you pass such method as argument, you can iterate over elements of such such list and use methods appropriate to Number class. You need to be aware that you cannot add any elements to such list. You are able to use list.get() method and that way, you're sure that you will get an instanceof Number class.
Such list is then called a producer. If you would need to add elements to list, instead of retrieving them, you would use <? super Number>. That rule is called PECS (Producer Extends Consumer Super).

"? extends ParentClass" makes Read only?

In the following code Java, I have created a list nums. I can assign the another list during the declaration. But new items cannot be added except the null. So, does it mean the nums is readonly? Why? Is it possible to add new items in that list?
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); //Generates error
nums.addAll(ints); //Generates error
nums.add(null); //works
System.out.println(nums.get(0)); //works
I have gone through this link. I can't get exact reason.
Is it possible to add new items in that list?
Nope... because that code doesn't know what it's "actually" a list of. Imagine if you could:
List<String> strings = new ArrayList<>();
List<? extends Object> objects = strings; // This is fine
objects.add(new Object()); // Fortunately this *isn't* valid...
System.out.println(strings.get(0).length()); // Or what would this do?
Basically, when you use a wildcard like ? extends T you can only get values out via the API... and when you use a wildcard like ? super T, you can only put the values in via the API - because that's what's safe.
No, it's not read-only... even though that is typically the intention.
Given a List<? extends Number> object, the compiler converts its type to List<X> where X is an unknown subtype of Number. Therefore, the object does have an add(X) method. We can call the method with an X argument... for example, null.
And since get() returns X, we could also call add() with a value from get() .... Directly invoking list.add(list.get(i)) won't work, even though it makes sense. We will need a little helper.
The classic example is Collections.reverse(List<? extends Object> list). This method will modify the list, despite the wildcard.
You can also call mutating methods like clear(), of course, on any list.
That being said, wildcard is indeed mainly for use-site variance, and most often, it conveys the intention from the API designer of whether a type-parameter is intended for in or out. For example, by declaring List<? super/extends Foo>, the API expresses that it intends to inject T in to, or, get T out of, the list.
It is a misconception that wildcard makes read/write-only. But this misconception works in most use cases. And the more people having this misconception, the more it becomes a convention...
see my article on wildcard - http://bayou.io/draft/Capturing_Wildcards.html
It's helps when you think of List<? extends Number> nums as a List of some type of thing that extends Number, but you can't be sure what. As such, everything you do with nums needs to be able to done to such a thing.
Adding null works because null can be cast into absolutely anything. Everything else you try to add will fail, because the compiler can't be 100% certain that the thing you're adding extends the thing the list is made of.
Instead of List<? extends Number> nums do List<Number> nums, because you can still put in anything that extends Number.
? doesn't mean "anything", it is closer to meaning "some specific but unknown".
Generics is compile time only.
So Compiler will decide what is actual type we are going to use.
List<? extends Number>
It means we are not sure what actual type of the object.
So Compiler not make sure what is the actual type that list have.

Why generic type is not applicable for argument extends super class for both?

Here is the problem that I have been being tried to find the solution.
We have two class definitions. One of two extends other one.
class T{}
class TT extends T{}
The requirement is that there should be a list keeps object extends T
List<? extends T> list = new ArrayList<>();
But the problem occures when I try to put a TT object ( barely seems it is a subclass of T )
into the list.
list.add(new TT());
Compilation Error Message
The method add(capture#2-of ? extends Cell) in the type List is not applicable for the arguments (Cell)
You can create a List<T> list = new ArrayList<T>(); directly, this can allow all subtypes of T into the list. This is actually little difficult to understand. when you declare it as
List<? extends T> list = ...
It means that it can allow any unknown subtypes of T into the list. But, from that declaration we cannot ensure which is the exact sub-type of T. so, we can only add null into it
List<? extends T> indicates that anything can comes out of it can be cast to T, so the true list could be any of the following:
List<T>
List<T2>
List<TT>
etc
You can see that even a new T cannot safely be added to such a collection because it could be a List<T2> which T cannot be put into. As such, such List cannot have non null entries added to them.
In this case you may simply want List<T>
So why would you ever use this?!
This contravariance can be useful for method parameters or returns, in which a collection will be read, rather than added to. A use for this could be to create a method that accepts any collection that holds items that are T, or extend T.
public static void processList(Collection<? extends Vector3d> list){
for(Vector3d vector:list){
//do something
}
}
This method could accept any collection of objects that extends Vector3d, so ArrayList<MyExtendedVector3d> would be acceptable.
Equally a method could return such a collection. An example of a use case is described in Returning a Collection<ChildType> from a method that specifies that it returns Collection<ParentType>.
The requirement is that there should be a list keeps object extends T
If you just want a List where you can store objects of any class that extend from T, then just create a List like this:
List<T> list = new ArrayList<T>();
The way you've created a list currently, will not allow you to add anything except null to it.
There are boundary rules defined for Java Generics when using WildCards
**extends Wildcard Boundary**
List means a List of objects that are instances of the class T, or subclasses of T (e.g. TT). This means a Read is fine , but insertion would fail as you dont know whether the class is Typed to T
**super Wildcard Boundary**
When you know that the list is typed to either T, or a superclass of T, it is safe to insert instances of T or subclasses of T (e.g.TT ) into the list.
In your example , you should use "super"
An addition to the other answers posted here, I would simply add that I only use wild cards for method parameters and return types. They're intended for method signatures, not implementations. When I put a wildcard into a variable declaration, I always get into trouble.

Why is it necessary to extend in case of read and super in write in generics wildcards?

I am having a hard time to understand the concept of generics wild cards.
As per my understanding <?> type unknown is introduced to resolve the co-variance not supported in generics and it should fit any type of collection and <?extends T> means that you can have collection of types T or the class which extends T.<?super T> means you can have collection of types T or super(s) of T.
Please correct me, if the above is wrong.
When I try to write it like this:
import java.util.*;
public class Gclass {
static Gclass t;
public void write(List< ?super String > lw){
lw.add("b");
}
public void read(List< ? extends String> lr){
String s=lr.get(2);
System.out.println(s);
}
public static void main(String[] args) {
t=new Gclass();
List<String> l=new ArrayList<String>();
l.add("a");
l.add("");
System.out.println(l);
t.write(l);
System.out.println(l);
t.read(l);
System.out.println(l);
}
}
It works but my places of doubt are:
As per my understanding both (extends and super) includes the type declared, so in this particular case as my List is of type String. I could interchange the extends and super, but I get compilation error?
In case of write ? super Object is not working? It should work as it is super of String?
I did not check for read as String can not be extended, but I think I'm also missing a concept here.
I've read all answers on SO related to this problem, but am still not able to have a good understanding about it.
String is indeed a bit of a bad example as it is a final class, but consider something like Number instead.
If a method takes a parameter of type List<? extends Number> then you can pass it a List<Number> or a List<Integer> or a List<BigDecimal> etc. Within the method body it is therefore fine to take things out of the list (as you know they must be instances of Number) but you can't put anything in because you don't know whether or not it's safe (the compiler can't let you risk putting an Integer into a List<Float>, for example).
Conversely if the method takes List<? super Number> then you can pass it a List<Number> or List<Object> - you can't take anything out of this list because you don't know what type it is*, but you do know that it'll definitely be safe to put a Number in.
* technically you can take things out but the only type you can assign them to is Object
As per my understanding both(extends and super) includes the type declared(String here), so in this particular case as my List is of type String... I could interchange the extends and super but i get compilation error?
You're right that both ? extends String and ? super String includes String. But you are missing the point that, ? super String also includes CharSequence, Object, which is not in bounds of ? extends String. You can add a String to a List<? super String>, b'coz whatever type that list is of, it can definitely refer to a String. But, you cannot add say an Integer to a List<? extends Number>, because the list can be a List<Float> actually.
In case of write ? super Object is not working? It should work as it is super of String?
Object is a super class of String will fit in where you have ? super String, and use Object for that. So, ? super String can capture Object, but ? super Object cannot capture String, as String is not a super type of Object. Think of it like this: "Actual type replaces the ?, and it must satisfy the rules attached to that ?.
List<? super String> means that lw holds a value of List with type argument which is String or it's superclass, so you can add a String value "b" (because it can be casted to list's type argument).
List<? extends String> means that lw holds a value of List with type argument which is String or it's subclasses, so values from lw can be casted to String.

Categories