Is there any way of imitating OR in Java Generics - java

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.

Related

How to specify the generic type of a collection?

I want to define a function which can convert a kind of Set to another, like convert HashSet to LinkedHashSet. Here is the function declaration. The sp is sharedpreferences.
public Set<String> decodeStringSet(String key, #Nullable Set<String> defaultValue, Class<? extends Set> cls){
Set<String> result = sp.getStringSet(key, defaultValue);
if(result == null){
return defaultValue;
}
else {
String[] array = result.toArray(new String[0]);
Set<String> a;
try {
a = cls.newInstance();
} catch (IllegalAccessException | InstantiationException var7) {
return defaultValue;
}
a.addAll(Arrays.asList(array));
return a;
}
}
However, the compiler remind me that "Unchecked assignment: '? extends java.util.Set' to 'java.util.Set<java.lang.String>'" on "a = cls.newInstance();". I don't know how to change cls to cls<java.lang.String>.
The warning is unavoidable. Isolate it in a helper method and toss the appropriate #SuppressWarnings at it. Or, refactor how this thing works. In general, the generics of Class<?> are weird and don't work well; if you try to write code that relies on the generics part to make it work, it's likely to result in many situations where you can't avoid these warnings, and the API is suboptimal.1
One tricky way to do what you're trying to do here in a one-size-fits-all way is so-called Super Type Tokens. You can search the web for this concept, because for what you're specifically doing here, STTs are overkill. What you are looking for, is a supplier.
You want the caller not to pass you the type of a set. No. You want the caller to pass you a piece of code that, if executed, creates the set.
While we're at it, let's get rid of the array, you're shifting the elements through that array for absolutely no sensible reason.
public <S extends Set<String>> S decodeStringSet(String key, #Nullable Set<String> defaultValue, Supplier<S> setMaker) {
Set<String> result = sp.getStringSet(key, defaultValue);
if(result == null) return defaultValue;
S a = setMaker.get();
a.addAll(result);
return a;
}
This code can be used as follows:
LinkedHashSet<String> mySet = decodeStringSet("myKey", null, LinkedHashSet::new);
Perhaps you're unfamiliar with this syntax. new LinkedHashSet() will, when you run that code, create a LinkedHashSet. In contrast, LinkedHashSet::new will, when you run that code, produce an object that can be asked to create a LinkedHashSet, by invoking its get() method. One does the act right this very moment. The other wraps 'do the act' into a little machine. You can hand the machine to other code, or press the button on the machine to make it do the act, and you can press the button as often as you feel like.
[1] Need some more explanations as to why relying on the generics of j.l.Class is awkward and not a good idea?
A class object simply cannot, itself, represent generics, whereas generics can represent generics. That is: List<List<String>> is perfectly fine. However, Class<List<String>> does not make sense. You can write it, (j.l.Class does not have hardcoded rules to keep sanity alive in the langspec), but it doesn't represent anything: There's just one class object that represents the type j.u.List. This one object cannot therefore represent the generics; you can't have one class object representing List<String> and another representing List<Integer>. Less important, but still annoying - there are things class objects can represent that generics cannot. int.class is types as Class<Integer> but this isn't quite right.
Hence, in your example, the compiler consider Class<? extends Set> as problematic; it's got a raw type inside the generics. However, it is technically correct, in that it is not possible to represent e.g. a Set<T>, merely 'a Set, whose generics are unknown, given that j.l.Class objects cannot represent them'.
Lastly, classes basically only produce (the P in PECS - which explains what the difference is between <Number>, <? extends Number>, and <? super Number>); it is mentally difficult to fathom the difference between Class<? extends String> and Class<String>, because it's an irrelevant difference, given that j.l.Class only produces. And yet, often you really do need to write Class<? extends String> because if you don't, the compiler refuses to compile your code for imaginary, irrelevant reasons. That's because, again, j.l.Class is not hardcoded in the lang spec: The compiler does not know that there is no effective distinction between Class<T> and Class<? extends T>, and java does not have a way to mark off a given generics param as forced Produces-only or some such.

Java Generic functions: Define a set of classes generic object must be

I'm writing a generic function in java, however, I can't seem to tell if there's any way of setting a list of classes that a Generic Object must be in.
Something like this:
public static <T in {String.class, Integer.class, Long.class}> Collection<T> test(Collection<T> val);
You can have Bounded Type Parameters like this for example:
public static <T extends String & Runnable> Collection<T> test(Collection<T> val);
But your example will not work since you have several classes and Java does not support Multiple inheritance.
Also, your examples String, Integer and Long are final so they will not possible to extend anyway.
No. You can't do that in java.
What you desire is an "OR" bound. Java allows "AND" bounding, eg:
List<T extends Runnable & Comparable<T>>
But the analogous "OR" is not supported:
List<T extends Integer | String> // doesn't compile
When you think about it, it doesn't make any sense. Use separate classes/methods for each type bound.
Unfortunately you can't do what you're trying to do in Java - if it allowed you to specify a generic from a list, you'd be able to write a function which operated either on Integers or ArrayLists, which makes no sense as they don't share common functionality. If you want to limit your method to certain types, either find a base class/interface which they all inherit from supporting the functionality you need (public static <T extends BaseClass> Collection<T> test(Collection<T> val);) or write a set of oveloaded methods, one for each type you want to support.
Well you can and can not at the same time.
In your specific example it is impossible.
But such an example would work:
public <T extends CharSequence & Comparable & Closeable> void go(){
For your case I would go with:
public <T extends Number & CharSequence> void go() // same rule applies as extend a class and implement as many interfaces as you want
You cannot do that. Generics is only for enforcing type safety (guaranteeing that the type can perform a particular method, etc.). There is no type-safety requirement that correspond to such an "OR" bound. Requirements on type safety only require an "AND" bound.

Java For loop and polymorphism

I was wondering how I could handle polymorphism in a for loop without using of "instanceof" like in C#.
Here is what I have :
An abstract class A :
public abstract class A
{
public abstract Map<Long, ? extends A> getNodes();
public abstract void setNodes(Map<Long, ? extends A> n);
}
B and C classes which extends A and implements abstract methods of A :
public class B
{
private Map<Long, C> childNodesC;
#Override
public Map<Long, ? extends A> getNodes()
{
return childNodesC;
}
#Override
public void setNodes(Map<Long, ? extends A> n)
{
for(C child : n)
childNodesC.put(child.getId(), child);
}
}
Is a for-loop like this one in setNodes() method, possible in Java ? I mean, is there a way for Java to understand that, in my loop, I want to iterate only over all C objects in a list of A objects (which here could be either B or C objects).
Or maybe I don't use polymorphism in the right way or something like that...or maybe this is a true case of "instanceof" operator usage :)
(Yeah you're right, I don't like "instanceof" operator, it makes me think that I didn't do the things correctly so I need to fix them with casts and instanceof. It looks "dirty" to me, but maybe I'm wrong and it is very common to use it !)
Thanks !
There are sometimes cases where you need to know of which subclass an instance is. We can't really determine if your case is one of those. But if you need to implement this you should consider using the Visitor Pattern and only implement the method of your wanted subclass. This way you avoid the 'dirty' instanceof checks.
That sort of loop-and-filter isn't available in Java. As for whether you're using polymorphism correctly, it's hard to say without a bit more context. If B.childNodesC needs to use a method that isn't available on A, then you probably need to just use instanceof to filter out the Cs. But otherwise, a more purely OO approach would be to define a method on A that answers some filtering question, and then have B's map have A values. Something like:
A.isSomethingInteresting() -> false
A.doSomething() { ... }
C.isSomethingInteresting() -> true
C.doSomething() overrides { ... }
B.setNodes would then see if each A is something interesting, and add it to its map only if it does. It would then invoke doSomething() on each of its As, and polymorphism would take it from there.
That sort of construct is not possible in Java (at least through Java 6). That loop expects every object to be an instance of C and does not act as a filter (and it should not). In general, if you are looping through something you want to get everything. If you want to further filter, then that's a separate action. There is no shame in using instanceof to do that (any more than there is shame in checking a property of an object).

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

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)?

Java generics parameter bounding to any of a range of types

Is there a syntax or workaround to constrain a generic type parameter to any of a range of types?
I am aware that you can constrain a type to be all of a range of types (ie AND logic):
public class MyClass<T extends Comparable<T> & Serializable> { } // legal syntax
Is there an OR logic version, ie something like this:
public class MyClass<T extends Comparable<T> | Serializable> { } // illegal syntax
If there isn't a syntax that supports this (I don't think there is), is there a workaround or approach that is a good pattern?
For some context, one example use case might be:
/** #return true if the obj is either has the same id, or if obj is the same as id */
public <T extends MyClass | String> boolean sameAs(T obj) {
if (obj instanceof String) return this.id.equals(obj);
if (obj instanceof MyClass) return this.id.equals(((MyClass)obj).id);
return false;
}
People seem to be getting hung up on the exact semantic of my method example above. Let's try this instead:
public class MyWrapper<T extends A | B> {
// my class can wrap A or B (unrelated classes). Yes I will probably use instanceof
}
EDITED:
I won't know at compile time which I might get (coming from external code), so I want to avoid having concrete classes for each type. Also, I have to give my class to a foreign system who invokes my class.method, but the other system can give me instances of a variety of classes, but a narrowly defined and known variety.
Some people have commented on instanceof being "impure". Well, one workaround is to use a factory method to pick my concrete class based on the class of the incoming object, but that factory method would have to use instanceof, so you're just moving the instanceof to another place - you still need the instanceof.
Or is this idea just not ever a good one?
No. It wouldn't make any sense unless all the types had a non-empty union type, e.g. an interface they all implemented, or a base class they all extended, in which case you just specify the union type.
public class MyWrapper<T extends A | B> {}
You can't do this for interfaces that you don't have control over, but for your own stuff you could use an empty marker interface:
interface AOrB {
}
interface A extends AOrB {
someMethodHere();
}
interface B extends AOrB {
someOtherMethodHere();
}
public class MyClass<T extends AOrB> {}
Regardless of what purists say, using instanceof is perfectly fine when you need it.
While Java has limited support for "intersection types" like T1 & T2, support for "union types" is scanty.
Generic types with wildcard are actually union types: G<? extends X> is the union of all G<S> where S is a subtype of X.
No support for union of arbitrary two types.
Java 7's multi-catch syntax looks like it supports union of arbitrary exception types
catch (IOException|SQLException ex){ .. }
but not really, the type of ex is a fixed super class, not a union of the two classes.
Using of instanceof is considered as not very good style of programming, and allowing you to use OR in generics implies you will use one.
The following code would do the same thing as in the provided example, but without runtime type checking and typecasts.
public boolean sameAs(MyClass obj) {
return this.id.equals(obj.id);
}
public boolean sameAs(String obj) {
return this.id.equals(obj);
}
NPE checking might be a good idea.

Categories

Resources