How Collection copy function works in java - java

I am trying to understand how Java Generic works. Here is the problems.
public static void main(String args[]){
List<Object> obj = Arrays.<Object>asList(23,"456",56.89);
List<Integer> intb = new ArrayList<>();
intb.add(234);
intb.add(345);
Collections.copy(obj,intb);
for(Object d : obj){
System.out.println(d);
}
}
This will work fine.But I implemented my own copy function like this
public static <T> void copy(List<? super T> des,List<? extends T> scr){
for(T f : scr){
des.add(f);
}
}
Then I used copy(obj,intb) instead of Collections.copy(obj,intb). Then I am getting errors. I don't understand why,But I know "? extends T" means any type that is a subtype of T and "? super T" means any type that is a supertype of T.

You cannot add anything to this fixed-length list:
List<Object> obj = Arrays.<Object>asList(23,"456",56.89);
You can only set new values to its elements (which is what Collections.copy() does). See also the Javadoc:
Returns a fixed-size list backed by the specified array.
What you probably intended to do was this:
List<Object> obj = new ArrayList<>(Arrays.asList(23,"456",56.89));

Well, a little bit late, but why your compiler complained about your code is not only because you used a fixed-size (immutable) List as a parameter in your copy method.
List<Object> obj = Arrays.<Object>asList(23, "456", 56.89);
Collections.copy(obj, intb);
It is also because of your (copy) method declaration.
public static <T> void copy(List<? super T> des,List<? extends T> scr) {
The declaration above has two lists with wildcards. When you use wildcard type <?>, you give message to the compiler that you are ignoring the type information. Whenever you pass arguments to a generic type, the java compiler tries to infer the type of the passed argument as well as the type of the generics and to justify the type safety. Now,(in your copy method) you are trying to use the add() method to insert an element in the list. Since des(your destination list) doesn't know the exact type of object it holds, it is risky to add elements to it. Generics was introduced in the language to ensure type safety in the first place. So you can not use methods like add that modifies the object. I hope the default implementation of the copy method in the java.util.Collections will help clarify it.
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
I know there already exists the same code block, but there was no explanation for what is the reason behind why we can't use methods like add on Lists with wildcards, and that is mainly to protect type safety.

In copy method
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
copy replace the value with index from index 0.
public static <T> void copy(List<? super T> des,List<? extends T> scr){
for(T f : scr){
des.add(f);
}
}
in this approach add into tail.

Related

What's the point of a write-only collection?

<? extends T> makes for a read-only collection
<? super T> makes for a write-only collection
I somehow get why use a read-only collection,for instance to use it in a multithreaded environment (any other cases?)
But why use a write-only collection? What's the point if you cannot read from it and use its values at some point? I know that you can get an Object out of it but that defies type safety.
Edit:
#Thomas the linked question (Difference between <? super T> and <? extends T> in Java) does show how to make a write only collection but does not answer 'why' would you need one in the first place.So it's not a duplicate
Statements like
<? extends T> makes for a read-only collection
<? super T> makes for a write-only collection
are just wrong. Wildcard element types do not say anything about the ability to read or write.
To show counter examples:
static <T> void modify(List<? extends T> l) {
l.sort(Comparator.comparing(Object::toString));
l.remove(l.size() - 1);
Collections.swap(l, 0, l.size() - 1);
l.add(null);
duplicateFirst(l);
}
static <U> void duplicateFirst(List<U> l) {
U u = l.get(0);
l.add(u);
}
shows quite some modifications possible for the List<? extends T>, without problems.
Likewise, you can read a List<? super T>.
static <T> void read(List<? super T> l) {
for(var t: l) System.out.println(t);
}
Usage restrictions imposed by ? extends T or ? super T are only in relation to T. You can not take an object of type T, e.g. from another method parameter, and add it to a List<? extends T>, because the list’s actual type might be a subtype of T. Likewise, you can not assume the elements of a List<? super T> to be of type T, because the list’s actual type might be a supertype of T, so the only assumption you can make, is that the elements are instances of Object, as every object is.
So when you have a method like
public static <T> void copy(List<? super T> dest, List<? extends T> src)
the method can not take elements from dest and add them to src (in a typesafe way), but only the other way round.
It’s important to emphasize that unlike other programming languages, Java has use site variance, so the relationship between the two list described above only applies to the copy method declaring this relationship. The lists passed to this method do not have to be “consumer of T” and “producer of T” throughout their entire lifetime.
So you can use the method like
List<Integer> first = List.of(0, 1, 2, 3, 7, 8, 9);
List<Number> second = new ArrayList<>(Collections.nCopies(7, null));
Collections.copy(second, first);
List<Object> third = new ArrayList<>(Collections.nCopies(11, " x "));
Collections.copy(third.subList(2, 9), second);
System.out.println(third);
Yes, copy was a real life example. Online demo
Note how the second list changes its role from consumer of Integer to producer of Object for the two copy invocations while its actual element type is Number.
Other examples for ? super T
Collections.fill(List<? super T> list, T obj)
Collections.addAll(Collection<? super T> c, T... elements)
To sum it up, in Java, rules like PECS are relevant for the declaration of methods, to determine the (typical) roles of the arguments within the method itself. This raises the flexibility for the caller, as it allows combining different invariant types, like the example of copying from a List<Integer> to a List<Number>.
But never assume that the generic types tell anything about the ability to read or write a collection.
Note that "write only collection" depends on the point of view.
Lets write a method that adds a bunch of numbers to a collection:
public static void addNumbers(List<? super Integer> target, int count) {
for (int i = 0; i < count; i++) {
target.add(i);
}
}
For this method the list target is a write only list: the method can only add numbers to it, it can not use the values that it added to the list.
On the other side there is the caller:
public static void caller() {
List<Number> myList = new ArrayList<>();
addNumbers(myList, 10);
double sum = 0;
for (Number n: myList) {
sum += n.doubleValue();
}
System.out.println(sum);
}
This method works with a specific list (myList) and therefore can read the values that addNumbers stuffed into it.
For this method the list is not a write only list, for this method it is an ordinary list.

Private helper method to capture wildcard type for generic methods

The following code does not compile in Eclipse. It says "The method putHelper(List,int,E) in the type Abc is not applicable for the arguments (List <.capture#8-of extends E>",int,E)"
private <E> void putHelper(List<E> list, int i, E value) {
list.set(i, value);
}
public <E> void put(List<? extends E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
I don't understand why it is so?
Because the code below works fine.
public <E> void put(List<? extends E> list,int fromPos, int toPos) {
putHelper(list,fromPos,toPos);
}
private <E> void putHelper(List<E> list,int i, int j) {
list.set(j,list.get(i));
}
And I understand that here the helper method is able to capture the wildcard type, but why not in the earlier code?
EDIT: In the third case, if I change type parameter in the put method to List<.? super E> and when I try to call the put() method from another method which takes a list, Eclipse doesn't compile it. It says, "The method put(List<.? super E>,int,E) in the type Abc is not applicable for the arguments (List <.capture#6-of extends E>",int,E)"
public static <E> void insertAndProcess(List<? extends E> list) {
// Iterate through the list for some range of values i to j
E value = list.get(i);
//Process the element and put it back at some index
put(list, i+1, value);
//Repeat the same for few more elements
}
private static <E> void putHelper(List<E> list, int i, E value) {
list.set(i, value);
}
public static <E> void put(List<? super E> list, int toPos, E value) {
putHelper(list, toPos, value);
}
Here, how can insertAndProcess() call put() method and use it in its implementation, while the user can still be able to call both these methods with say ArrayList<.Integer>?
This is because of the Get and Put Principle also known by the acronym PECS which stands of Producer Extends, Consumer Super.
This is explained in this SO question: What is PECS (Producer Extends Consumer Super)?
But basically:
public <E> void put(List<? extends E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
<? extends E> can't be used here because the List is being used as a consumer (it is taking elements) so it should use super instead of extends.
public <E> void put(List<? super E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
EDIT
In your 2nd case, List is acting as a producer because it is producing elements via the call to get() so you can use extends.
However, in your 3rd example, you are both getting and putting into the same list so I don't think you can use wildcards at all.
This compiles:
public static <E> void insertAndProcess(List<E> list) {
// Iterate through the list for some range of values i to j
E value = list.get(i);
// Process the element and put it back at some index
putHelper(list, i+1, value);
// Repeat the same for few more elements
}
Note that since we don't need to use any wildcards anyway because we are getting and setting from the same list so the type E must be the same no matter what it is.
Generics are sometimes a bit difficult. Try to analyze it step by step.
Imagine - in your first example (that doesn't compile) - you call the put method with the type variable E replaced by Number. As you are constraining the input parameter list with List<? extends E> it could be a List<Integer> for example. The parameter value is of type E (remember: E is Number), so it could be a Double for example. And this must not be allowed because you would try to add a Double into a List<Integer>.
In the second example you only have a constraint on the input parameter list. No other parameter is dependent on E. Setting and getting on a list will always work because the elements in question must be of the same type.
A solution:
Always remind the acronym PECS. See Wildcard (Java). That means you should declare the put method as following (in your first example):
public <E> void put(List<? super E> list, int toPos, E value) {
putHelper(list, toPos, value);
}
List<E> will accept only E class objects where as List<? extends E> can accept any sub-class of E.
When you say a method can accept only List<E> passing List<? extends E> will confuse the compiler because it does not know which type of Object your list will actually contain.
Note that in java, this is illegal:
List<E> list = new ArrayList<? extends E>();
E.g. List<Number> list = new ArrayList<Integer>();
In the second example, your list expects any sub-class of E and what your passing is list of E objects so its allowed.
E.g. List<? extends Number> list = new ArrayList<Integer>();

Remove elements from collection

What I want to do is remove all elements in a collection that are less than a specified object. This is what I have:
static void removeAllLessThan(Collection c, Object x) {
for(Object a : c) if(a.compareTo(x) < 0) c.remove(a);
}
This does not work because Object has no compareTo method. What I want to know is how should I compare between objects? Also what is the natural comparator? Thank you.
using Collection<Comparable> instead of Collection,and implement Comparable to all your items in the collection. And change your method like:
static void removeAllLessThan(Collection<Comparable> c, Comparable x) {
for (Iterator<Comparable> it = c.iterator(); it.hasNext();)
if (it.next().compareTo(x) < 0)
it.remove();
}
Start by using generics, and let the caller declare what type of object he wants to filter by:
static <T> void removeAllLessThan(Collection<T> collection, T t) {...}
This isn't enough, however. You need to use a Comparator<T> to provide the ordering.
static <T> void removeAllLessThan(Collection<T> collection,
Comparator<T> comparator, T t) {...}
Then, allow the user some flexibility when working with inheritance. He has to do the equivalent of t1 < t2, but the comparator can be of any supertype of T, and the collection can be of anything that extends T:
static <T> void removeAllLessThan(Collection<? extends T> collection,
Comparator<? super T> comparator, T t) {...}
Then, there is a mistake with the deletion process. The only mechanism that can delete from a collection while iterating over it is the Iterator. Anything else risks a ConcurrentModificationException.
static <T> void removeAllLessThan(Iterable<? extends T> iterable,
Comparator<? super T> comparator, T t) {
for (Iterator<? extends T> it = iterable.iterator(); it.hasNext();) {
if (comparator.compare(it.next(), t) < 0) {
it.remove();
}
}
}
Note the signature change.
Finally, this is a very specific method. You will need to write lots of nearly identical methods like removeIfGreaterThan, removeIfEqualIgnoringCase, etc. Write a generic removeIf method, with signature
public <T> removeIf(Iterable<? extends T> iterable,
Predicate<? super T> predicate){...}
Predicate is an interface provided by lots of libraries that has just a boolean eval method.
There are two ways to solve this problem.
First, you can use Comparable Interface, which means that the method should be changed into:
static void removeAllLessThan(Collection<Comparable> c, Comparable x) {
for(Comparable a : c) if(a.compareTo(x) < 0) c.remove(a);
}
An object should be comparable to have a method called comparedTo.
Second, you can implement a Comparator to judge which is bigger. If you don't want the object to be comparable, which means you don't want to change the existing code to let it implement Comparable, this is a better way. But the code will be change into:
static void removeAllLessThan(Collection c, Object x, Comparator comp) {
for(Object a : c) if(comp(a, x) < 0) c.remove(a);
}
Here is the javadoc of Comparable and Comparator.

Java Generics - are these two method declarations equivalent?

Given some class SomeBaseClass, are these two method declarations equivalent?
public <T extends SomeBaseClass> void myMethod(Class<T> clz)
and
public void myMethod(Class<? extends SomeBaseClass> clz)
For the caller: yes, they are equivalent.
For the code inside the method: no.
The difference is that within the code of the first example you can use the type T (for example to hold an object created by clz.newInstance()), while in the second you can't.
No, they're not. With the first definition, you can use the type T inside the method definition, e.g. create an ArrayList<T> or return T. With the second definition, that's not possible.
Bounded wildcards are subject to certain restrictions to avoid heap pollution.
When you use the wildcard ? extends X you know you can read generic information, but you cannot write.
For instance
List<String> jedis = new ArrayList<String>();
jedis.add("Obiwan");
List<? extends CharSequence> ls = jedis
CharSequence obiwan = ls.get(0); //Ok
ls.add(new StringBuffer("Anakin")); //Not Ok
The compiler avoided heap pollution when you tried to add a CharSequence (i.e. StringBuffer) to the collection. Because the compiler cannot be sure (due to wildcards) that the actual implementation of the collection is of type StringBuffer.
When you use ? super X you know you can write generic information, but you cannot be sure of the type of what you read.
For instance
List<Object> jedis = new ArrayList<Object>();
jedis.add("Obiwan");
List<? super String> ls = jedis;
ls.add("Anakin"); //Ok
String obiwan = ls.get(0); //Not Ok, we can´t be sure list is of Strings.
In this case, due to wildcards, the compiler knows that the actual implementation of the collection could be anything in the ancestors of String. Thus it cannot guarantee that what you will get will be a String. Right?
This same restrictions are the ones you would be subject too in any declaration with bounded wildcards. These are typically known as the get/put principle.
By using a type parameter T you change the story, from the method standpoint you are not using a bounded wildcard but an actual type and therefore you could "get" and "put" things into instances of the class and the compiler would not complain.
For instance, consider the code in Collections.sort method. If we write a method as follows, we would get a compile error:
public static void sort(List<? extends Number> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<? extends Number> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((Number)a[j]); //Not Ok, you cannot be sure the list is of Number
}
}
But if you write it like this, you can do the work
public static <T extends Number> void sort(List<T> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<T> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
And you could even invoke the method with collections bounded with wildcards thanks to a thing called capture conversion:
List<? extends Number> ints = new ArrayList<Integer>();
List<? extends Number> floats = new ArrayList<Float>();
sort(ints);
sort(floats);
This could not be achieved otherwise.
In summary, as others said from the caller standpoint they are alike, from the implementation standpoint, they are not.
No. On top of my head, I can think of the following differences:
The two versions are not override-equivalent. For instance,
class Foo {
public <T extends SomeBaseClass> void myMethod(Class<T> clz) { }
}
class Bar extends Foo {
public void myMethod(Class<? extends SomeBaseClass> clz) { }
}
does not compile:
Name clash: The method myMethod(Class) of type Bar has the same erasure as myMethod(Class) of type Foo but does not override it
If a type parameter appears more than once in a method signature, it always represents the same type, but if a wildcard appears more than once, each occurrence may refer to a different type. For instance,
<T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
compiles, but
Comparable<?> max(Comparable<?> a, Comparable<?> b) {
return a.compareTo(b) > 0 ? a : b;
}
does not, because the latter may be called by
max(Integer.MAX_VALUE, "hello");
The method body may refer to the actual type used by the caller using a type parameter, but not using a wildcard type. For instance:
<T extends Comparable<T>> T max(T... ts) {
if (ts.length == 0) {
return null;
}
T max = ts[0];
for (int i = 1; i < ts.length; i++) {
if (max.compareTo(ts[i]) > 0) {
max = ts[i];
}
}
return max;
}
compiles.
#Mark #Joachim #Michael
see the example in JLS3 5.1.10 Capture Conversion
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list){ ... }
so the <?> version can do anything the <T> version can do.
this is easy to accept if the runtime is reified. a List<?> object must be a List<X> object of some specific non-wildcard X anyway, and we can access this X at runtime. So there's no difference using a List<?> or a List<T>
With type erasure, we have no access to T or X, so there's no difference either. We can insert a T into a List<T> - but where can you get a T object, if T is private to the invocation, and erased? There are two possibilities:
the T object is already stored in the List<T>. so we are manipulating elements themselves. As the reverse/rev example shows, there's no problem doing this to List<?> either
it comes out-of-band. There's other arrangement made by the programmer, so that an object somewhere else is guaranteed to be of type T for the invocation. Unchecked casting must be done to override compiler. Again, no problem to do the same thing to List<?>

How come generic type parameter says "extends" Comparable not "implements"? [duplicate]

This question already has answers here:
Why is "extends T" allowed but not "implements T"?
(9 answers)
Closed 3 years ago.
I tried to write generic function that remove the duplicate elements from array.
public static <E extends Comparable<E>> ArrayList<E> removeDuplicate(E[] arr) {
//do quicksort
Arrays.sort(arr);
ArrayList<E> list = new ArrayList<E>();
int i;
for(i=0; i<arr.length-1; i++) {
if(arr[i].compareTo(arr[i+1]) != 0) { //if not duplicate, add to the list
list.add(arr[i]);
}
}
list.add(arr[i]); //add last element
return list;
}
As you can see you can't pass primitive type like int[] array since I am comparing elements by compareTo() method that defined in Comparable interface.
I noticed the first line (method declaration):
public static <E extends Comparable<E>> ArrayList<E> removeDuplicate(E[] arr) {
How come it says "extends Comparable" ?
Comparable is an interface so why is it not "implement Comparable"? This is first time I wrote generic function so I'm bit confused about such detail. (any wondering would prevent me from understanding..)
EDIT: Found this article related to this topic.
http://www.tutorialspoint.com/java/java_generics.htm
This is just the convention chosen for generics. When using bounded type parameters you use extends (even though it might mean implements in some cases) or super.
You can even do something like <E extends Comparable<E> & Cloneable> to define that the object that would replace the type parameter should implement both those interfaces.
If You want to use the thing that implements You just write is as generic parameter
class Bar extends Foo<String> { /* Code */}
The wildcard that You are talking about are three
"? extends Type": Denotes a family of subtypes of type Type. This
is the most useful wildcard
"? super Type": Denotes a family of supertypes of type Type
"?": Denotes the set of all types or any
You method should look like
public static <T extends Comparable<? super T>> Collection<T> sort(T[] list) {
Collection<T> list = new ArrayList<T>();
//do quicksort
Arrays.sort(arr);
Collection<T> list = new ArrayList<T>();
int i;
for(i=0; i<arr.length-1; i++) {
if(arr[i].compareTo(arr[i+1]) != 0) { //if not duplicate, add to the list
list.add(arr[i]);
}
}
list.add(arr[i]); //add last element
//btw how do You know that last is not duplicate
return list;
}
For detail please visit this page
For one thing, E might be an interface.

Categories