Generics - Legal alternative for (elements instanceof List<? extends Comparable>) - java

I have this method which unique parameter (List elements) sets elements to a ListModel, but I need to make a validation to see if the generic type implements comparable and since such thing like:
if (elements instanceof List<? extends Comparable>)
is illegal, I don't know how to do the proper validation.
Update
I already have done this validation using:
(elements.size() > 0 && elements.get(0) instanceof Comparable)
but I want to know if is there a cleaner solution for that, using for example reflection?
Thanks in advance.

The generic type of a list is erased at runtime. For this to work you need to either require the parameter in the method signature or test each element individually.
public void doSomething(List<? extends Comparable> elements) {}
OR
for (Object o : elements) {
if (o instanceof Comparable) {}
}
If you have control over the code, the former is preferred and cleaner; the later can be wrapped in a utility method call if needed.

That's not possible. instanceof is a runtime operator whereas generic information is lost at runtime (type-erasure).

I'm not a Generics guru, but to my understanding the reason you can't do that is that at runtime, there's no distinction between an ArrayList and, say, an ArrayList<String>. So it's too late to perform the test you want.
Why not just declare your method to accept a List<? extends Comparable> instead of a List?
In particular, the way you phrased your question makes it sound like you expect the list to always contain homogeneous elements, but a plain old List doesn't give you any sort of assurance like that.

To your update: simply making sure that one element implements Comparable is not enough (what if the other ones don't?) And making sure that all of the elements implement Comparable is also not enough to validate (what if they are of different classes that implement Comparable but cannot compare with each other?).
But the bigger question is, why bother validating at runtime anyway? What benefit does that give compared to simply trying to use it and then seeing that it fails (i.e. throws an Exception, which maybe you can catch)?

Related

Is the unbounded wildcard type used only to create references?

I have seen a lot of cases where in, the ? type is used only to create references. And we are not able to add any Objects other than null. So, is the use of '?', only to create references?
Also, what is the need / use of giving the option to add a null? They could simply have implemented with no add() method at all, right? Any reason for giving the option of adding null into List < ? > ?
List is a generic interface, and the same interface regardless of the generic type. As such, all implementors are required to redefine all methods in it. As far as being able to add null into an "unbounded" list, it's not as much a matter of methods as much as a requisiste of respecting the interface:
the unbound generic wildcard allows a reference to a List (or other generic class) to be passed around to methods without requiring a compile-time knowledge of the specific type it will contain. However, the contract of the generic must still be respected. This poses no big problem for read operations, since whatever is in the List, it will always (also) be a java.lang.Object. On the other hand, insert operations are almost impossible, since lacking informations about the accepted types, no type can be accepted - e.g. a List can only accept strings, but an Object could be anything else - a Number for example, and thus cannot be accepted safely.
Null works safely since (assuming the List accept null values), it will be the only value that's always valid to be put inside the list (a null can be cast to any valid type).
Edit: just since i noticed i didn't actually answer your question: yes, the <?> wildcard (and the extended forms as well <? extends X> and <? super X> are only valid when defining references, and cannot be used in generic instantiation.
Firstly, null is a member of all types. That's part of the language specification that pre-dates generics, so you can' do anything about that.
As for the use of ?, you can't * instantiate* a wildcard-typed generic class, that you can't do this:
List<? extends Number> list = new ArrayList<? extends Number>(); // error
because it does't make sense. The wildcard type is used to tell the compiler "I don't know what the type of the list will be, but it will be bounded by Number". However, when the code executes, a List with a type bounded by Number will be assigned to the variable.
Wildcards are most often seen as parameters:
public static void doSeomthing(List<? extends Number> list) {
// use the list knowing only that the elements are a subclass of Number
// but knowing which exact class they are
}

Practical usage of wildcard generics in Java

I recently had an exam on Java, and there was a wide section about wildcard generics in Java. However, there is very little said about their usage in practice. When should we use them? Let's see a typical usage:
void check(Collection<? extends Animal> list) {
// Do something
}
What the documentation says, that this collection does not allow to add any elements to the list. So basically wildcards can be used for making collections read-only. Is that their only usage? Is there any practical need for that? For the last four years I took part in a lot of programming projects in Java, but I haven't seen any project that would use extensively such a feature as wildcard.
So, from the practical point of view, are there any situations when wildcard generics are unavoidable and necessary?
So, from the practical point of view, are there any situations when
wildcard generics are unavoidable and necessary?
I don't think they are 'unavoidable and necessary' because the Java compiler erases them anyway. However, when using them you get the benefit of a tighter type check during compile-time and you avoid type casting. Who wants to type cast anyway? :)
Guidelines for Wildcard Use
Type Erasure
void check(Collection<? extends Animal> list) {
list.add(new Animal()); // compile time error
list.add(new Dog()); // compile time error. Dog is subclass of Animal class.
}
Java has develop such generics because to disallow the programmar to code whatever they want otherwise if it is allowed then later they will find a mess in run-time environment.
Sometime in programming you will get a scenario where your method check would not wan't to add element in the list but want to read those element.
You can only add null values.
In brief, what you are saying is wrong.
It has nothing to do to "make collections read-only".
We can still add elements to the input list, because Collection did declare a add(E) method.
The wildcard is straight-forward I think: You actually want to constraint the input type, because your logic is only reasonable for certain type.
For your example, your check maybe using some method of Animal
void check(Collection<? extends Animal> list) {
// Do something
for (Animal a : list) {
a.checkAge(); // checkAge() is method of Animal
}
}
Without ? extends Animal, the above code will not work, as the incoming list can be collection of anything (not Animal).
Therefore, we want to make sure the incoming collection to Collection or Collection etc, so that our code actually make sense as we are retrieving elements from the list and treated the element as Animal.

Is there any way of imitating OR in Java Generics

EDIT: I changed a bit the example for getting the idea:
Like
<Integer or Float>
...without having to create a common interface and make a subclass for Integer and Float to implement it
If not, something like this would maybe have more sense and be useful
<E extends Number> <E = (Integer|Float)>
If ? is a wildcard why should not we allowed to restrict certain types?
It's not possible and I hardly see any value in it. You use generics to restrict type, e.g. in collections. With or operator you know as much about the type as much you know about the most specific supertype of both of them, Object in this case. So why not just use Object?
Hypothetical:
List<E extends String or Number> list = //...
What is the type of list.get(0)? Is it String or Number? But you cannot have a variable of such type. It cannot be String, it cannot be Number - it can only be... Object.
UPDATE: Since you changed your example in question to:
<Integer or Float>
why won't you just say:
<Number>
? Note that Number has methods that allow you to easily extract floatValue() and intValue(). Do you really need the exact type?
Note that you can use and operator:
<E extends Serializable & Closeable>
And that makes perfect sense - you can use variable of type E where either Serializable or Closeable is needed. In other words E must extend both Serializable and Closeable. See also: Java Generics Wildcarding With Multiple Classes.
In very extreme cases (pre-Java 7 without AutoCloseable), I would have liked to be able to do that, too. E.g.
<E extends Connection or Statement or ResultSet>
That would've allowed me to call E.close(), no matter what the actual type was. In other words, E would contain the "API intersection" of all supplied types. In this case it would contain close(), and all methods from java.sql.Wrapper and java.lang.Object.
But unfortunately, you cannot do that. Instead, use method overloading, e.g.
void close(Connection c);
void close(Statement s);
void close(ResultSet r);
Or plain old instanceof
if (obj instanceof Connection) {
((Connection) obj).close();
}
else if (obj instanceof Statement) { //...
Or fix your design, as you probably shouldn't have to intersect APIs of arbitrary types anyway
I don't see a real use for it... But anyways, I believe the closest you'd get to it is extending common interfaces for the possible implementations.

What if I implement List and call add in a method that accepts List<? extends SuperType>

I have read that the following code snippet will result in a compiler error
void tryAddingToList(List<? extends SuperType> list) {
list.add(new SubType());
}
Now my question is:
Who exactly sets the restriction and how is the restriction set? Does the compiler specifically check for the add method call in such a method implementation?
If yes, what if I implement my own List and instead of add, introduce a new addToList method that does the same thing as add, and call that in the tryAddingToList method?
Even better, what if I implement my get method such that it also "secretly" adds something to the list (don't ask me why anyone would do that; I'm just curious).
You should use super instead of extends here.
void tryAddingToList(List<? super SubType> list) {
list.add(new SubType());
}
Assume there are 3 types SuperType, SubType1, SubType2. In your original code, List<? extends SuperType> could be List<SubType2>, and you can't add a SubType1 to List<SubType2>.
You should cast SubType to SuperType explicitly. Because not all objects of SuperType are SubType(may be typed other sub-classes). This may give you some hint. Good luck.
Yes, it's indeed the compiler that applies the restriction. Most of the information (not all) will be erased when actually compiled to byte code. You should interpreted generics as extra information for the developer, so we don't make silly mistakes.

Java Collections of Interfaces

I'm writing a small API to deal with objects that have specific 'traits' In this case, they all have an interval of time and a couple of other bits of data, So I write an interface TimeInterval with some getters and setters.
Now most of these API methods deal with a Set or List of Objects. Internally these methods use the Java Colletions Framework (HashMap/TreeMap in particular). So these API methods are like:
getSomeDataAboutIntervals(List<TimeInterval> intervalObjects);
Couple of Questions:
a) Should this be List<? extends TimeInterval> intervalObjects instead?
Is it mostly a matter of style? The one disadvantage of taking strictly an interface that I can see is, you need to create your list as a List<TimeInterval> rather than List<ObjectThatImplementsTimeInterval>.
This means potentially having to copy a List<Object..> to List<TimeInterval> to pass it to the API.
Are there other pros & cons to either approach?
b) And, one dumb question :) The collections framework guarantees I always get out the same instance I put in, the collections are really a collection of references, correct?
1) Yes.
Method parameters should be as general as possible. List<? extends A> is more general than List<A>, and can be used when you don't need to add things to the list.
If you were only adding to the list (and not reading from it), the most general signature would probably be List<? super A>
Conversely, method return types should be as specific as possible. You rarely to never want to return a wildcard generic from a method.
Sometimes this can lead to generic signatures:
<T extends MyObject> List<T> filterMyObjects(List<T>)
This signature is both as specific and as general as possible
2) Yes, except possibly in some rare very specific cases (I'm thinking of BitSet, although that isn't technically a Collection).
If you declare your list as List<? extends A>, then you can pass in any object which static type is List<X>, where X extends A if A is a class, or X implements A id A is an interface. But you'll not be able to pass in a List or a List<Object> to it (unless A is Object) without force-casting it.
However, if you declare the parameter as a List<A>, you'll only be able to pass lists which static type is strictly equivalent to List<A>, so not List<X> for instance. And by "you are not able to do otherwise", I really mean "unless you force the compiler to shut up and accept it", which I believe one should not do unless dealing with legacy code.
Collections are really collections of references. The abstraction actually is that everything you can put in a variable is a reference to something, unless that variable is of a primitive type.
1) I would recommend ? extends TimeInterval. Because of Java's polymorphism, it may not actually make a difference, but it is more robust and better style
2) Yes
a) No. List<? extends TimeInterval> will only accept interfaces that extend the interface TimeInterval. Your assertion that "you need to create your list as a List<TimeInterval> is wrong, unless I misunderstand your point. Here's an example:
List<List> mylist= new ArrayList<List>();
mylist.add(new ArrayList());
b) Yes.
Should this be List intervalObjects instead?
You only do that if you want to pass in a List<TimeIntervalSubclass>. Note you can put instances of subclasses of TimeInterval into a List<TimeInterval>. Keep in mind that the type of the list is different than the types in the list.
If you do List<? extends A> myList -- that only affects what you can assign to myList, which is different than what is in myList.
And, one dumb question :) The collections framework guarantees I
always get out the same instance I put in, the collections are really
a collection of references, correct?
When you create a collection Map myMap = new HashMap(), myMap is a reference to the underlying collection. Similarly, when you put something into a collection, you are putting the reference to the underlying object into the collection.

Categories

Resources