I have an interesting discrepancy between javac and Eclipse IDE compiler, and can't figure out who's right. So, the code below compiles with javac, however Eclipse tells me that the static initializer's invocation of "exportAll" is wrong, 'cause:
The method exportAll(Iterable< X.Stat< ? extends Number>>) in the type X is not applicable for the arguments (Collection< capture#1-of ? extends X.Stat>)
Who's right? javac or Eclipse?
import java.util.Map;
public class X {
interface Stat<T> {
}
public static void exportAll(Iterable<Stat<? extends Number>> vars) {
}
public static Map<Double, ? extends Stat> getPercentiles() {
return null;
}
static {
exportAll(getPercentiles().values());
}
}
You can't compile your example - you are calling a non-static method getPercentiles from the static initializer, so I'll assume that it is a static method, too.
In any case, your compiler would at least spit out an "unchecked" warning if you compile with -XLint:unchecked (Stat takes a type parameter!). I assume you would like the following:
public class X {
interface Stat<T> {
}
public static void exportAll(Iterable<? extends Stat<? extends Number>> vars) {
}
public static Map<Double, ? extends Stat<Double>> getPercentiles() {
return null;
}
static {
exportAll(getPercentiles().values());
}
I assume that your percentiles are an arbitrary subclass of Stat<Double>, therefore I declared them as ? extends Stat<Double> in the Map. So the values() call will return a Collection<? extends Stat<Double>>.
Collection implements Iterable, therefore we are safe on that side.But Collection<? extends Stat<Double>> is not covered by Iterable<Stat<? extends Number>>, therefore we need to declare the argument as Iterable<? extends Stat<? extends Number>>.
The beauty (well, except for the syntax) of having exportAll take Iterable<? extends Stat<? extends Number>> is that your Map could contain all sorts of ? extends Stats<N> where N is a subclass of Number.
Your Map<Double, ? extends Stat>.values() will have a type of Collection<? extends Stat>. This Stat is really Stat<?>. Your Iterable requires that the Stat not just be any old Stat<?> but rather Stat<? extends Number>. You would have to change your getPercentiles() to be Map<Double, ? extends Stat<? extends Number>>.
public static void exportAll(Iterable<Stat<? extends Number>> vars) {
} // ^ this must match
// your values type on the map
public Map<Double, ? extends Stat<? extends Number>> getPercentiles() {
return null;
}
#emboss here's what I would do in those cases whenever I could:
class Main {
static interface Something<E> {
void doSomething();
}
static class ConcreteSomething<E> implements Something<E> {
E data;
ConcreteSomething(E data) {
this.data = data;
}
public void doSomething() {
System.out.println(data);
}
}
public static void main(String[] args) {
List<Something<Number>> list = new LinkedList<Something<Number>>();
list.add(new ConcreteSomething<Number>(Math.PI)); // an autoboxed Double
list.add(new ConcreteSomething<Number>(new Integer(5))); // an Integer
for(Something<Number> s : list) s.doSomething();
}
}
It doesn't compile in javac. (after adding static to getPercentiles)
Get your facts straight; don't waste other people's time.
Kids today, too much ADD.
Related
I have a generic interface defined as:
public interface ItemService<T extends Slicer, E extends ItemSlice> {
E getItemHistory(final String id, final T slicer);
}
And an implementation:
public class DynamoDbItemService implements ItemService<DynamoDbSlicer, DynamoDbItemSlice> {
public DynamoDbItemSlice getItemHistory(final String id, final DynamoDbSlicer slicer) {
}
}
Here are the definitions of the four classes referenced above:
public interface Slicer {
Map<String, ? extends Serializable> pointer();
}
public class DynamoDbSlicer implements Slicer {
public Map<String, AttributeValue> pointer() {
}
}
public interface ItemSlice extends Slice<Item> {
}
public interface Slice<T> {
List<T> data();
Slicer next();
}
public class DynamoDbItemSlice implements ItemSlice {
publi ImmutableList<Item> data() {}
public DynamoDbSlicer next() {}
}
I would like to reference the ItemService interface but for it to be bound to the DynamoDbItemService implementation so I can swap it out if necessary which I can do like so:
ItemService<? extends Slicer, ? extends ItemSlice> itemService = new DynamoDbItemService itemService();
but if I try to use itemService like this:
ItemSlice slice = itemService.getItemHistory(itemId, DynamoDbSlicer.first(1));
slice = itemService.getItemHistory(itemId, slice.next());
I get these two compilation errors:
Error:(231, 82) java: incompatible types: item.pagination.DynamoDbSlicer cannot be converted to capture#1 of ? extends pagination.Slicer
Error:(238, 62) java: incompatible types: pagination.Slicer cannot be converted to capture#2 of ? extends pagination.Slicer
I understand from this question that ? wildcards cannot be identical so my question is - can I do what I want - work with the interface? If so, how? Or am I approaching this incorrectly?
I have asked two previous questions related to this which have helped along the way (first and second)
I don't see a reason why the following wouldn't work for you:
ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("", new DynamoDbSlicer());
But if you would like to make the code as modular as possible you can use this method to perform an unchecked cast (pure evil some say) and get the result you want:
public static void main(String[] args) {
ItemSlice slice = getMySlice(new DynamoDbItemService());
}
#SuppressWarnings("unchecked")
public static <T extends Slicer, E extends ItemSlice> E getMySlice(ItemService<T, E> service) {
return service.getItemHistory("", (T) new DynamoDbSlicer());
}
And then of course there is the solution of passing the type inference responsibility to the actual field that is storing the value. I myself would go for this solution, as I think it offers the most flexibility:
public class DynamoDbItemService<T extends Slicer, E extends ItemSlice> implements ItemService<T, E>
ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("", new DynamoDbSlicer());
There is technique to define class, containing a method, returning a value of the same type as class -- self recursion.
But using this, is it possible to stop recursion?
Some code:
public class StopSelfRecursion {
// base class
static class Class1<Self extends Class1<Self,T>, T> {
public Self getMyself() {
return (Self) this;
}
}
// derived 1
static class Class2<Self extends Class2<Self, T>, T> extends Class1<Self, T> {
}
// derived 2
static class Class3<Self extends Class2<Self, T>, T> extends Class2<Self, T> {
}
// want to stop recursion; want Class4 has only one parameter
static class Class4<T> extends Class3<Class3, T> {
}
public static void main(String[] args) {
Class1<?, Integer> v1 = new Class1<>();
Class2<?, Integer> v2 = new Class2<>();
Class3<?, Integer> v3 = new Class3<>();
System.out.println(v1.toString());
System.out.println(v2.toString());
System.out.println(v3.toString());
}
}
If it is not possible to stop recursion, then why?
If there is no logic reason of being not able to stop it, then what about adding this feature in next versions of Java?
For example, keyword ThisClass can be added or something.
I'm not 100% clear what the issue is, beyond fixing the compilation issue. You can do that by simply changing the definition of Class4 to this:
static class Class4<T> extends Class3<Class4<T>, T>
^^
[Live example]
I have some code like this
import com.google.common.collect.Sets;
public void handleInput(Set<Object> conditions){
Set<Set<Object>> powerSet = Sets.powerSet(conditions);
...
}
This works fine. But I want to do this:
public void handleInput(Set<? extends Object> conditions){
Set<Set<? extends Object>> powerSet = Sets.powerSet(conditions);
...
}
so I can get the powerset of objects that are subclasses of object. But this won't compile and I get the error:
Type mismatch: cannot convert from Set<Set<capture#1-of
? extends Object>> to Set<Set<? extends Object>>
How can I achieve this goal?
EDIT: I guess it has something to do with the generic type getting erased at compile time, so that the compiler can't know that powerSet won't add something illegal to the sets it's creating. I've reworked the client, by casting all the inputs to Object, and removing the wildcard altogether. Is this the best way? Thanks!
In this case it doesn't make any sense - since all Java classes extend java.lang.Object at some point.
So ? extends Object is redundant.
But speaking of Sets.powerSet, this works like a charm:
public class TestClass {
public static class A {}
public static class B extends A {}
public static class C extends B {}
public Set<? extends Set<? extends A>> exampleMethod(Set<? extends A> input) {
return Sets.powerSet(input);
}
public static void main(String[] args) {
final TestClass testClass = new TestClass();
final A a = new A();
final B b = new B();
final C c = new C();
System.out.println(
testClass.exampleMethod(
ImmutableSet.of(a, b, c)
)
);
}
}
as #slnowak notes, when you are extending Object, the code is really redundant.
However, to understand the Exception and avoid it...
public void handleInput(Set<? extends Object> conditions){
Set<? extends Set<? extends Object>> powerSet = Sets.powerSet(conditions);
...
}
this will compile and, more usefully, you can restrict the types in your conditions argument using this method, for instance - you could have:
public void handleInput(Set<? extends Number> conditions){
Set<? extends Set<? extends Number>> powerSet = Sets.powerSet(conditions);
...
}
and this would prevent you passing in sets that had non-numeric types and warn you of this at compile time.
public abstract class Mother {
}
public class Daughter extends Mother {
}
public class Son extends Mother {
}
I need a Map which keys are one of Daughter or Son classes, and which values are lists of objects of one of those two classes, respectively.
For example:
/* 1. */ map.put(Daughter.class, new ArrayList<Daughter>()); // should compile
/* 2. */ map.put(Son.class, new ArrayList<Son>()); // should compile
/* 3. */ map.put(Daughter.class, new ArrayList<Son>()); // should not compile
/* 4. */ map.put(Son.class, new ArrayList<Daughter>()); // should not compile
I tried Map<Class<T extends Mother>, List<T>>, but it does not compile.
Map<Class<? extends Mother>, List<? extends Mother>> does compile, but the cases 3. and 4. do compile too while then shouldn't.
Is it even possible?
I don't think it's possible to encode this in the type, I'd do it with a custom class
class ClassMap<T> {
private Map<Class<? extends T>, List<? extends T>> backingMap = new HashMap<>();
public <E extends T> void put(Class<E> cls, List<E> value) {
backingMap.put(cls, value);
}
#SuppressWarnings("unchecked")
public <E extends T> List<E> get(Class<E> cls) {
return (List<E>)backingMap.get(cls);
}
}
It's safe to suppress warnings here as long as you don't leak the backingMap reference outside this class.
Assuming you're looking for a single map, no this is not possible.
In Java, the Collections class contains the following method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
Its signature is well-known for its advanced use of generics,
so much that it is mentioned in the Java in a Nutshell book
and in the official Sun Generics Tutorial.
However, I could not find a convincing answer to the following question:
Why is the formal parameter of type Collection<? extends T>, rather
than Collection<T>? What's the added benefit?
Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:
public class ScratchPad {
private static class A implements Comparable<A> {
public int compareTo(A o) { return 0; }
}
private static class B extends A {}
private static class C extends B {}
public static void main(String[] args)
{
Collection<C> coll = null;
B b = Scratchpad.<B>min(coll);
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c) {
return null;
}
//public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
// return null;
//}
}
Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>, but perhaps there is an implicit inference where B would be the inferred type.
One benefit of the ? is that it prohibits additions of items to the Collection
I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.
They are including it here so it can become the new convention where every generic should be extended by ?
A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?
But a static method doesn't need to (at least the parameters, the return value should always)
This is to support a legacy signature of the method in Java 1.4 ( and before ).
Prior to Java 5 the signature for these methods was
public static Object min ( Collection c );
With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object & the signature would be
public static Comparable min ( Collection c );
and legacy code would break.
This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6
Building on the comments I put on Mark's answer, if you have something like
class Play {
class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
class B extends A {
}
class C extends A {
}
public static <T extends Object & Comparable<? super T>> T min(
Collection<? extends T> c) {
Iterator<? extends T> i = c.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static List<? extends A> getMixedList() {
Play p = new Play();
ArrayList<A> c = new ArrayList<A>();
c.add(p.new C());
c.add(p.new B());
return c;
}
public static void main(String[] args) {
ArrayList<A> c = new ArrayList<A>();
Collection<? extends A> coll = getMixedList();
A a = Play.min(coll);
}
}
It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c) ). If you leave min(Collection<T>) without the extends part then Play.min(coll) will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c) which isn't as clear.