How can I construct an EnumSet of generic varargs? - java

Assume I want to do something like the following:
public static <V> Set<V> setOf(V... elem)
{
Set<V> set = null;
if (elem[0] instanceof Enum)
set = Sets.newEnumSet(elem, elem[0].getClass()); OR
set = EnumSet.<V>noneOf(elem[0].getClass());
return set;
}
Neither of these, or several other variations, seem to work. Can someone explain to me what's going on? I have looked at How do I get the type object of a genericized Enum? and some other similar questions, but I still can't get this to work.

First of all, you need to make sure the type V is restricted to be an enum type; you can do this by specifiying that V must extends Enum<V>.
Then, you will need to provide the Class of the enum type. Due to type-erasure, you won't be able to derive it at run-time. This is needed because, to construct a new empty EnumSet, you need to specify the type of the elements.
Finally, you have several ways to create the set, but the simplest might be to use the Stream API:
#SafeVarargs
public static <V extends Enum<V>> Set<V> setOf(Class<V> enumClass, V... elem) {
return Arrays.stream(elem).collect(Collectors.toCollection(() -> EnumSet.noneOf(enumClass)));
}
Note that if you can guarantee that there will be at least 1 element, you could use EnumSet.copyOf(Arrays.asList(elem)) without the need to pass the class.

If you can't bound the generic parameter to V extends Enum<V>, you can make compilable code as follows:
public <V> Set<V> setOf(V... elem) {
Set<V> set = null;
if (elem[0].getClass().isEnum()) {
set = (Set<V>) EnumSet.copyOf((Collection<Enum>)Arrays.asList(elem)) ;
}
return set;
}
Of course there are unsafe cast warnings.
I also changed the check of the type to:
if (elem[0].getClass().isEnum())
which IMHO is cleaner.

Related

In Java, can I reuse the generics types from an interface parameter to create a different class which also requires generic types? And if so, how?

Here is an overview of the Java code I have:
// An interface and an implementation class:
public interface MyInterface<T1, T2> { ... }
public class MyImplementation implements MyInterface<int, String> { ... }
// Another class
public class MyClass<T3, T4> { ... }
// Function I want to call
void doStuff(MyInterface i) {
MyClass<int, String> n;
}
// I want to call the function like this:
MyInterface mi = new MyImplementation();
doStuff(mi);
What I can't figure out is if I can get MyClass<int, String> n; to somehow use the generic types from the MyImplementation class passed in to doStuff()? In this case, n would automatically use <int, String> because that's what MyImplementation uses.
Yes, you can.
Let's move away from nebulous hypotheticals and take real classes: Collection<T>, Map<K, V>, and Function<F, T>. Let's say you want to write a method in the Map type (or interface, doesn't matter, a signature is a signature) that takes a 'key converter' (a thing that converts Ks into something else), returning a collection of the something-else, which consists of each key in the map, thrown through the converter, and added to a collection.
class MapImpl<K, V> implements Map<K, V> {
public <T> Collection<T> convertKeys(Function<K, T> converter) {
List<T> out = new ArrayList<T>();
for (K key : keySet()) out.add(converter.apply(key));
return out;
}
}
A lot of concepts are being used here:
The implementation doesn't lock in the types of K and V. You don't just inherit typevars from interfaces you implement, so, MapImpl gets its own K,V which are also used as the K,V for the interface. That covers line 1.
The convertKeys method introduces its own unique typevar, in addition to the K,V it already gets. That's because.. well, that's how the method works: The map's keys have some type, the values have some other type, and this converter converts to some third type. Three types: K, V, and T. A method can introduce new vars just for the method, that's what the <T> is all about in line 2.
Any time you name a type name, if that type is generified, you MUST toss <> after it and put in appropriate things. Or don't put in appropriate things which means: Hey, compiler, figure it out if you can (the so called diamond operator). In your snippet, you use MyInterface i as method param type and that's bad: MyInterface has generics, so it must have <> behind it. In this case, you have to add things because there is no way the compiler can try to figure things out.
Going back to your code, it might look like:
public <K, V> void doStuff(MyInterface<K, V> i) {
MyClass<K, V> n;
}
NB: Remember, generics link things. That final snippet is simply saying: There is a link between the first typearg of the MyInterface part of the 'i' parameter's type, and the first typearg of the MyClass part of the 'n' local variable. I don't know what that type is. I do know it is the same type. Generics are completely useless unless the typevar occurs in 2 or more places.
NB2: If you then want to get real fancy, you start thinking about co/contra/invariance. For example, in the key converter story, if you have a converter that can convert any object into something else that'd be cool too. In fact, a converter that can convert either Ks, or any supertype of Ks, that'd all be suitable. So, really, you end up with: public <T> Collection<T> convertKeys(Function<? super K, ? extends T> converter) {} - but that kind of advanced variance engineering is a nice bonus, feel free to skip those bits in your source until you run into trouble because you didn't take it into consideration.

In Java, what can a wild card do that regular generics cannot do?

I am new to Java. In this document they give this as a use case for using wildcard:
static void printCollection(Collection c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
This is their solution:
static void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
But I could do the same without a wild card:
static <T> void printCollection(Collection<T> c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
Can someone show me a simple use case where regular generics won't work but a wild card will?
Update: The answers over here When to use wildcards in Java Generics? do NOT tell us the need for wildcard. In fact its the other way around.
One thing wildcards allow us to do is declare types that are agnostic towards a particular type parameter, for example a "list of any kind of list":
List<List<?>> listOfAnyList = ...;
listOfAnyList.add( new ArrayList<String>() );
listOfAnyList.add( new ArrayList<Double>() );
This is impossible without a wildcard:* because the element lists may have different types from each other.
And if we try to capture it, we will find that we can't:
static <E> void m(List<List<E>> listOfParticularList) {}
m( listOfAnyList ); // <- this won't compile
Another thing wildcards allow us to do that type parameters cannot is set a lower bound. (A type parameter can be declared with an extends bound, but not a super bound.**)
class Protector {
private String secretMessage = "abc";
void pass(Consumer<? super String> consumer) {
consumer.accept( secretMessage );
}
}
Suppose pass was instead declared to take a Consumer<String>. Now suppose we had a Consumer<Object>:
class CollectorOfAnything implements Consumer<Object> {
private List<Object> myCollection = new ArrayList<>();
#Override
public void accept(Object anything) {
myCollection.add( anything );
}
}
The problem is: we can't pass it to a method accepting Consumer<String>. Declaring Consumer<? super String> means that we can pass any consumer which accepts a String. (Also see Java Generics: What is PECS?.)
Most of the time, wildcards just let us make tidy declarations.
If we don't need to use a type, we don't have to declare a type parameter for it.
* Technically also possible with a raw type, but raw types are discouraged.
** I don't know why Java doesn't allow super for a type parameter. 4.5.1. Type Arguments of Parameterized Types may hint that it has something to do with a limitation of type inference:
Unlike ordinary type variables declared in a method signature, no type inference is required when using a wildcard. Consequently, it is permissible to declare lower bounds on a wildcard […].
T stands for the generic type of that data structure. In your last example, you don't use it, and its NOT an actual type (for example String), and because you don't use it it doesn't really matter in this case.
For example, if you had a Collection and tried to pass it to a method that accepts a Collection, that works because there is no type T on the classpath so its considered a variable. If you tried passing the same Collection to a method that accepts a Collection, that would not work because you have String on your classpath so its not a variable.
Take List as the example.
List<?> can be the parent class of List<A>.
for instance,
List<B> bList = new ArrayList<>(); // B is a class defined in advance
List<?> list = bList;
you can never use <T> in this situation.
<?> has the wildcard capture.
here,
void foo(List<?> i) {
i.set(0, i.get(0));
}
the code above cannot be compiled. You can fix it:
void foo(List<?> i) {
fooHelper(i);
}
// wildcard can be captured through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
see more, http://docs.oracle.com/javase/tutorial/java/generics/capture.html
I can only think of the two currently, later may update.

How can I use both method and class type parameters in single constraint?

I'll try to illustrate my problem in the following simplified example:
public class DataHolder<T> {
private final T myValue;
public DataHolder(T value) {
myValue = value;
}
public T get() {
return myValue;
}
// Won't compile
public <R> DataHolder<R super T> firstNotNull(DataHolder<? extends R> other) {
return new DataHolder<R>(myValue != null ? myValue : other.myValue); }
public static <R> DataHolder<R> selectFirstNotNull(DataHolder<? extends R> first,
DataHolder<? extends R> second) {
return new DataHolder<R>(first.myValue != null ? first.myValue : second.myValue);
}
}
Here I want to write generic method firstNotNull that returns DataHolder parametrized by common supertype of type parameter T of the this and other argument, so later I could write e.g.
DataHolder<Number> r = new DataHolder<>(3).firstNotNull(new DataHolder<>(2.0));
or
DataHolder<Object> r = new DataHolder<>("foo").firstNotNull(new DataHolder<>(42));
The problem is that this definition of firstNotNull is rejected by compiler with message that super T part of type constraint is illegal (syntactically).
However without this constraint definition is also wrong (obviously), because in this case T and R are unrelated to each other.
Interestingly, definition of similar static method selectFirstNotNull is correct and the latter works as expected. Is it possible to achieve the same flexibility with non-static methods in Java type system at all?
It isn't possible to do this. The authors of Guava ran into the same issue with Optional.or. From that method's documentation:
Note about generics: The signature public T or(T defaultValue) is
overly restrictive. However, the ideal signature, public <S super T> S or(S), is not legal Java. As a result, some sensible operations
involving subtypes are compile errors:
Optional<Integer> optionalInt = getSomeOptionalInt();
Number value = optionalInt.or(0.5); // error
FluentIterable<? extends Number> numbers = getSomeNumbers();
Optional<? extends Number> first = numbers.first();
Number value = first.or(0.5); // error
As a workaround, it is always safe to cast an
Optional<? extends T> to Optional<T>. Casting either of the above
example Optional instances to Optional<Number> (where Number is the
desired output type) solves the problem:
Optional<Number> optionalInt = (Optional) getSomeOptionalInt();
Number value = optionalInt.or(0.5); // fine
FluentIterable<? extends Number> numbers = getSomeNumbers();
Optional<Number> first = (Optional) numbers.first();
Number value = first.or(0.5); // fine
Since DataHolder is immutable like Optional, the above workaround will work for you too.
See also: Rotsor's answer to Bounding generics with 'super' keyword
I don't think there is any easy and type-safe way to do this. I've tried a couple of approaches, but the only working approach that I found is to start with a super type generic instance, and make the method pretty simple like this:
public DataHolder<T> firstNotNull(DataHolder<? extends T> other) {
return new DataHolder<T>(myValue != null ? myValue : other.myValue);
}
Now you have to change your invocation to:
DataHolder<Number> r = new DataHolder<Number>(3).firstNotNull(new DataHolder<>(2.0));
You might argue that this doesn't really answer your question, but this is the simplest thing you're going to get, or better resort to a static method approach. You can surely come up with some highly convoluted (and type-unsafe) methods to do so, but readability should be of major concern here.
Try changing your method as follows:
public <R> DataHolder<R> firstNotNull(DataHolder<? super T> other) {
return new DataHolder<R>((R)(this.myValue != null ? myValue : other.myValue));
}
WARNING: This compiles and gives the appearance of being properly checked for the most part but is not perfect. It will restrict the input parameters, but not the output. This cannot be done perfectly. In some ways you might be better off doing this unchecked rather than giving the illusion of being checked. Here are some examples:
DataHolder<BigDecimal> a = new DataHolder<>(new BigDecimal(34.0));
DataHolder<Number> b = new DataHolder<>(new Integer(34));
DataHolder<String> c = new DataHolder<>("");
DataHolder<Number> p = a.firstNotNull(b); // WORKS (good)
DataHolder<BigDecimal> q = b.firstNotNull(a); // FAILS (good)
DataHolder<BigDecimal> r = b.firstNotNull(c); // FAILS (good)
DataHolder<String> s = a.firstNotNull(b); // WORKS (not good!!!)

Declaring generic methods, clarification needed

Consider the following 2 method declarations:
1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData> execute();
Both seem to return back a list of objects that extend MetaData.
What is the difference between them please?
In the first case you will allow Java to use type inference and infer the type of T at each call site.
In the second case you will always get a List<? extends MetaData> and so won't be able to assign it to a variable of any narrower type like List<IntegerMetaData>.
If there are any subtypes of MetaData then the first version can only return an empty list or null. The second version may return a list containing instances of MetaData and its subtypes.
Example: Say A and B are subtypes of MetaData and execute returns a list containing an instance of A. The caller might have called execute like so:
List<B> list = execute(); // the second version does not allow this
The caller said he wanted a list of Bs, but got a list containing an A. Due to type erasure the implementation of execute has no way of knowing what the caller asked for. Thus the first version can't be implemented (except to return null or an empty list).
In example 1, you cannot must return a List whose generic type is T, e.g.:
#Override
public <T extends MetaData> List<T> execute() {
List<T> l = new ArrayList<T>();
return l;
}
In example 2, you can return a List whose generic type is just MetaData, e.g.:
#Override
public List<? extends MetaData> execute2() {
List<MetaData> l = new ArrayList<MetaData>();
return l;
}
What is the difference? In the first case, the method has a generic type, T and you must return something that relates to that type. In the second case, you just return a generic type, but the method itself does not have a generic type.

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Categories