I'm trying to make a generic class with one type parameter, class MyClass<E>, that has a class variable of a second generic class with two type parameters, SecondClass<V, E>. Since for my code it really doesn't matter what the type of V is, I declare the type of that variable as SecondClass<?, E> var. At some point in the implementation of MyClass I call a method on var that returns a V, public V foo(E e), and then I pass this object of type V to another method of var, public int bar(V v). However, this doesn't compile because of reasons I only vaguely understand, but I believe it is explained in here.
Apparently, the capture-of-? returned by foo is different from the the capture-of-? required by bar. But why? Whatever the actual type of V is, it must be the same for both methods, since they are invoked on the same instance. What am I missing here?
Ultimately, what I would like to know is this: what do I need to change in order to make the code compile, without adding V to the type parameters of MyClass? (I don't want to enforce users of MyClass to specify the type of V since it shouldn't matter)
To give you a more concrete example, here's a simplified version of what I'm working on. As you may already have guessed by the type parameters, it concerns graphs. MyClass translates to EdgePainter and SecondClass translates to Graph. With this code, the compile error is in the first line of EdgePainter.getColor(E).
class Graph<V, E>
{
public V getTarget(E edge)
{
return null;
}
public int getInDegree(V vertex)
{
return 0;
}
}
class EdgePainter<E>
{
private static final Color COLOR_FOR_MANY_EDGES = Color.RED;
private static final Color COLOR_FOR_FEW_EDGES = Color.BLUE;
private Graph<?, E> graph;
public EdgePainter(Graph<?, E> aGraph)
{
graph = aGraph;
}
public Color getColor(E edge)
{
// My compiler says:
// The method getInDegree(capture#3-of ?) in the type
// Graph<capture#3-of ?,E> is not applicable for the arguments
// (capture#4-of ?)
int degree = graph.getInDegree(graph.getTarget(edge));
if (degree > 10)
return COLOR_FOR_MANY_EDGES;
else
return COLOR_FOR_FEW_EDGES;
}
}
You can capture the wildcard by invoking a generic method.
public Color getColor(E edge) {
return getColorInternal(graph, edge);
}
private <X> Color getColorInternal(Graph<X, E> g, E e) {
int degree = g.getInDegree(g.getTarget(e));
// ...
}
This is a typical scenario. You need a type argument for the implementation, but want to hide it from API users. If many methods are affected it can be helpful to define a separate, perhaps nested, class EdgePainterInternal. This internal implementation has the second type parameter G and the publicly visible implementation EdgePainter delegates all calls to an instance of EdgePainterInternal.
Related
Can I require classes implementing an interface to have a certain static field or method and access/invoke that field or method through a generic type argument?
I have an interface, Arithmetical<T>, which specifies several functions like T plus(T o) and T times(T o). I have as well a Vector<N extends Arithmetical<N>> class, which is intended for vectors (of variable dimension) with components of type N. I ran into an issue, however, when trying to implement the dot product.
I want to implement the method N dot(Vector<N> o). For this, I plan to start with whatever N's zero is and iterate through both Vector<N>s' List<N>s, adding the product of each pair of elements to my total. Is there a way to specify in Arithmetical<T> that all implementing classes must have a static (and preferably final) field ZERO and start dot(Vector<N> o)'s body with something along the lines of N sum = N.ZERO;?
If not, what other approaches might there be to this problem? I want to allow 0-dimensional vectors, so I can't just begin by multiplying the vectors' first components. Is there a way to instantiate an object of a generic type, so I can merely specify a T zero() method in Arithmetical<T>?
I have a reason for not using Java's numerical types—I want to have vectors with complex components.
Here's Arithmetical:
public interface Arithmetical<T> {
public T plus(T o);
public T minus(T o);
public T negate();
public T times(T o);
public T over(T o);
public T inverse();
// Can I put a line here that requires class Complex (below) to define ZERO?
}
Vector:
public class Vector<N extends Arithmetical<N>> {
private List<N> components;
public Vector<N>(List<N> cs) {
this.components = new ArrayList<N>(cs);
}
public N dot(Vector<N> o) {
// Here's where I need help.
}
}
And Complex:
public class Complex implements Arithmetical<Complex> {
public static final Complex ZERO = new Complex(0, 0); // Can I access this value through N if <N extends Arithmetical<N>>?
private double real;
private double imag;
public Complex(double r, double i) {
this.real = r;
this.imag = i;
}
/* Implementation of Arithmetical<Complex> (and some more stuff) not shown... */
}
I'm quite new to Java (and programming in general); I will likely not understand complex (ha) explanations and workarounds.
Thanks!
(Python is a suggested tag... Huh.)
You need a "zero" for every possible implementation type. A constant in the interface won't do, because a constant cannot be overridden and must remain the same.
The solution is to add a new method to your Arithmetical interface:
public T zero();
Each implementation is forced to implement this and return its own version of zero. In this case, you're using it as a starting point for adding; it's the additive identity.
The Complex class implementation would look like this.
#Override
public Complex zero() {
return ZERO;
}
If your instances are mutable, then don't use a constant; just return new Complex(0, 0).
Another idea is to borrow from what Streams do when reduce-ing items and combining them to one single item -- take an identity value that represents the initial state, i.e. no items collected yet -- zero.
public N dot(Vector<N> o, N identity) {
N dotProduct = identity;
// Perform operations on each item in your collection
// to accumulate and return a dot product.
}
The caller will have to supply the identity value.
Complex dotProduct = vectorOfComplex.dotProduct(otherVector, new Complex(0, 0));
Can I put a line here that requires class Complex (below) to define ZERO?
No. The best you can do is to define an interface, for example:
interface ZeroProvider<A extends Arithmetical<A>> {
A zero();
}
and then supply a compatible instance of that where you need to provide a zero, for example:
class ComplexZeroProvider implements ZeroProvider<Complex> {
public Complex zero() { return new Complex(0, 0); }
}
There's something you can do sometimes using reflection in situations like this. If you put the following method in the Vector class, it will invoke a static method N.zero() (with caveats, below):
protected N zero() {
try {
Type s = getClass().getGenericSuperclass();
#SuppressWarnings("unchecked")
Class<N> n = (Class<N>) ((ParameterizedType) s).getActualTypeArguments()[0];
Method zero = n.getMethod("zero");
return n.cast(zero.invoke(null));
} catch (RuntimeException | ReflectiveOperationException x) {
// probably better to make a custom exception type
throw new IllegalArgumentException("illegal type argument", x);
}
}
However, it's important to understand what this is actually doing. This is getting the type argument from the class file of the direct superclass of this. In other words, there must actually be a superclass of this with an actual type argument (which is a class).
The usual idiom then is that you'd create all of your vectors like this:
new Vector<Complex>() {}
instead of this:
new Vector<Complex>()
Or you'd declare subclasses like this:
public class Vector<N> {
// ...
public static class OfComplex extends Vector<Complex> {
}
}
Since you need an actual superclass with a type argument which is a class, instantiations like in the following examples will fail:
new Vector<Complex>()
new Vector() // never use this anyway
new Vector() {} // never use this anyway
// also, you can't do stuff like this:
public Vector<T> copy() {
return new Vector<T>(this) {};
}
In your case I think the suggestions in the other answers are better, but I wanted to post this answer along with the proper explanation and caveats which are sometimes not included. There are cases where this technique is actually good, mainly when you have pretty tight restrictions on how the class in question is extended. Guava TypeToken will also do some of the reflection for you.
Also, this is the best Java can do at doing exactly what you're asking for (at the moment), so it's worthwhile to point out just as a comparison.
How to overload a Function with generic parameter in Java 8?
public class Test<T> {
List<T> list = new ArrayList<>();
public int sum(Function<T, Integer> function) {
return list.stream().map(function).reduce(Integer::sum).get();
}
public double sum(Function<T, Double> function) {
return list.stream().map(function).reduce(Double::sum).get();
}
}
Error: java: name clash:
sum(java.util.function.Function<T,java.lang.Double>) and
sum(java.util.function.Function<T,java.lang.Integer>) have the same erasure
Benji Weber once wrote of a way to circumvent this. What you need to do is to define custom functional interfaces that extend the types for your parameters:
public class Test<T> {
List<T> list = new ArrayList<>();
#FunctionalInterface
public interface ToIntFunction extends Function<T, Integer>{}
public int sum(ToIntegerFunction function) {
return list.stream().map(function).reduce(Integer::sum).get();
}
#FunctionalInterface
public interface ToDoubleFunction extends Function<T, Double>{}
public double sum(ToDoubleFunction function) {
return list.stream().map(function).reduce(Double::sum).get();
}
}
Another way is to use java.util.function.ToIntFunction and java.util.function.ToDoubleFunction instead:
public class Test<T> {
List<T> list = new ArrayList<>();
#FunctionalInterface
public int sum(ToIntFunction function) {
return list.stream().mapToInt(function).sum();
}
public double sum(ToDoubleFunction function) {
return list.stream().mapToDouble(function).sum();
}
}
The example you present in your question has got nothing to do with Java 8 and everything to do with how generics work in Java. Function<T, Integer> function and Function<T, Double> function will go through type-erasure when compiled and will be transformed to Function. The rule of thumb for method overloading is to have different number, type or sequence of parameters. Since both your methods will transform to take a Function argument, the compiler complains about it.
That being said, srborlongan has already provided one way to resolve the issue. The problem with that solution is that you have to keep modifying your Test class for each and every type of operation (addition,subtraction,etc) on different types (Integer,Double, etc). An alternate solution would be to use method overriding instead of method overloading :
Change the Test class a bit as follows :
public abstract class Test<I,O extends Number> {
List<I> list = new ArrayList<>();
public O performOperation(Function<I,O> function) {
return list.stream().map(function).reduce((a,b)->operation(a,b)).get();
}
public void add(I i) {
list.add(i);
}
public abstract O operation(O a,O b);
}
Create a subclass of Test that will add two Integers.
public class MapStringToIntAddtionOperation extends Test<String,Integer> {
#Override
public Integer operation(Integer a,Integer b) {
return a+b;
}
}
Client code can then use the above code as follows :
public static void main(String []args) {
Test<String,Integer> test = new MapStringToIntAddtionOperation();
test.add("1");
test.add("2");
System.out.println(test.performOperation(Integer::parseInt));
}
The advantage of using this approach is that your Test class is in line with the open-closed principle. To add a new operation such as multiplication, all you have to do is add a new subclass of Test and override the operation method to multiply two numbers. Club this with the Decorator pattern and you can even minimize the number of sub-classes that you have to create.
Note The example in this answer is indicative. There are a lot of areas of improvement (such as make Test a functional interface instead of an abstract class) which are beyond the scope of the question.
#srborlongan 's solution won't work very well :)
See a similar example - Comparator methods - comparingDouble(ToDoubleFunction), comparingInt(ToIntFunction), etc. The methods have different names, because overloading is not a good idea here.
The reason is, when you do sum(t->{...}), the compiler is unable to infer which method to call; actually it needs to resolve method overloading first, to pick one method, before inferring the type of the implicit lambda expression (based on that method's signature)
This is disappointing. In the earlier stage, Java8 had a more sophisticated inference engine, and Comparator had overloaded comparing() methods; and sum(t->{...}) would be correctly inferred too. Unfortunately, they decided to simply it :( And here we are now.
Rule of thumb for overloading methods with functional arguments: the arities of the functional interfaces must be different, unless both are 0.
// OK, different arity
m1( X->Y )
m1( (X1, X2)->Y )
// not OK, both are arity 1
m2( X->Y )
m2( A->B )
m2( t->{...} ); // fail; type of `t` cannot be inferred
// OK! both are arity 0
m3( ()->Y )
m3( ()->B )
The reason why overloading with arity 0 is OK is that the lambda expressions won't be implicit - all argument types are known (because there's no argument!), we don't need contextual information for inferring the lambda type
m3( ()-> return new Y() ); // lambda type is ()->Y
m3( ()-> return new B() ); // lambda type is ()->B
I have this types:
abstract class ControlGraphic {
//...
}
class PrecisionControlGraphic extends ControlGraphic {
//...
}
class AccuracyControlGraphic extends ControlGraphic {
//...
}
I have a method that returns a List<T> where T is PrecisionControlGraphic or AccuracyControlGraphic depending on type parameter:
private <T extends ControlGraphic> List<T> getGraphics() {
List<T> graphics = new LinkedList<T>();
for (ControlGraphic graphic : getGraphicsFromDB())
graphics.add( (T) graphic);
return graphics;
}
The code below works properly:
List<PrecisionControlGraphic> precisionGraphics = getGraphics();
for (PrecisionControlGraphic graph : precisionGraphics) { ... }
I'd like to know why this other one doesn't:
for (PrecisionControlGraphic graph : getGraphics()) { ... }
Thanks.
The method signature is saying "you can set T to any subclass of ControlGraphic", and that is why the assignment typechecks (because the compiler finds a type T that works, in fact the type is taken from the assigned-to variable).
The "other one" (direct loop) doesn't work because the type T could be any subclass of ControlGraphic, not necessarily PrecisionControlGraphic. The direct loop doesn't work because the type checker in Java does not do full inference like in functional programming languages. The type of the "graph" variable would have to literally be "any subclass of ControlGraphic" for it to be accepted (and this could actually be arranged by making the type a type parameter of the enclosing method).
Another possibility, as pointed out by #Adrian Leonhard is to annotate the call to getGraphics with the desired type:
for (PCG graph : this.<PCG>getGraphics())
But, basically, with any of these solutions, you are misusing generics. All you know in getGraphics is that you are dealing with ControlGraphic objects, and so that method should return List<ControlGraphic>, and your code should perform explicit casting at the places in the code at which the derived type is known.
As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.
I am trying to use a combination of wildcards in the type of the receiver and in the type of an argument to a method in Java. The context is that of defining a container. Now, the type Container should not admit insertions whatsoever, since this type does not specify the type of the contained objects. However, if the underlying data structure allows it, there should be a way for searching an object of type T, or of any other type that extends T.
Here is a code snippet that demonstrates the problem. Any ideas on how I can achieve this design goal in Java?
public class Main {
public static class Container<T extends Item> {
public void insert(T t) {
System.out.println("Inserting " + t);
}
public <R extends T> int find(R r) {
return r.hashCode();
}
}
public static class Item {
// Nothing here
}
public static class ExtendedItem extends Item {
// And nothing here...
}
public static class Client {
public static void main(String[] args) {
useContainerOfItem();
useContainerWildCardOfItem(new Container<Item>());
Container<? extends Item> c;
c = new Container<Item>(); // OK. type of c, is a super type of Container<Item>
c = new Container<ExtendedItem>(); // OK. type of c, is a super type of Container<ExtendedItem>
useContainerWildCardOfItem(c);
}
private static void useContainerOfItem() {
Container<Item> c = new Container<Item>();
c.insert(new Item()); // OK. We can insert items
c.insert(new ExtendedItem()); // OK. We can insert items
c.find(new Item()); // OK. We can find items in here.
c.find(new ExtendedItem()); // OK. We can also find derived items.
}
private static void useContainerWildCardOfItem(Container<? extends Item> c) {
c.insert(new Item()); // Error: expected. We should not be able to insert items.
c.insert(new ExtendedItem()); // Error: expected. We should not be able to insert anything!
c.find(new Item()); // Error. Why??? We should be able to find items in here.
c.find(new ExtendedItem()); // Error. Why??? We should be able to find items in here.
}
}
}
The error message is telling you precisely what is the issue. Your find method is using a generic R extends T, and the T in this case is ?, so the compiler has no way of checking your supplied R (an Item) to check if it extends "capture#6-of ?".
I think your find method is parameterized incorrectly. In particular, you almost certainly don't mean to use extends in the declaration R extends T.
You seem to accept that with the wildcarded generic parameter <? extends Item>, you are not going to be able to insert anything, because the compiler cannot assert that any particular object you pass in conforms to the bounds (with the single exception of the null literal). Remember that this is not because of any specials semantics of an insert-type method, but solely because of the interface.
Your find method cannot be called for the exact same reason. Bear in mind that declaring <R extends T> and then declaring a parameter as type R, is exactly the same as declaring the parameter of type T. (Think about it the allowed values in both cases). And as you've seen above, no non-null objects can be accepted as an instance of T in your wildcarded case.
I think you may have intended to write your find method as <R super T>. In this case, the compiler can know for sure that no matter actual type of T is, it's Item or a subtype - and so Item or any of its superclasses (including Object) will always be valid for R and thus can be passed in. However, in this case, since Object is a valid substitution for the bounds, and all objects can be accepted for an Object parameter, this method is then equivalent to
public int find(Object r) {
return r.hashCode();
}
This is fact is entirely the semantics you're trying to capture - you don't need the generic bounding as they don't provide any bounds. Typically it's only ever worth using super in generic bounds when it's a nested generic parameter, e.g. you're accepting a collection as a parameter that you want to add objects of type T to (in which case you'd want a Collection<? super T>).
Alternatively, reading through your own answer to the question, my assessment in the above paragraph may be slightly incorrect. There are, then, three different restrictions you could try to apply to the type of the argument to the find method:
Anything is allowed (i.e. Object).
The argument must be an instance of the highest possible bound for the contained types (so if Container is defined as Container<T extends Item>, you declare the method to take a parameter of type Item).
The types must match exactly (i.e. T).
Generally speaking I would recommend to go as general as is possible - if you need to call methods that are defined in the Item class in order to test the match, then your hands are tied and you'll have to go with the second option. However, if you don't need to do this, then accept arguments of type Object to give callers the most flexibility.
Along those lines, there is essentially no possible argument for ever taking option 3 - you won't get any extra functionality in your method (since you can't call any more specific methods than you could in the second case), and you're simply restricting clients. Consider the following:
MyItem a = new MyItem();
Container<MyItem> c = new Container<MyItem>();
c.insert(a);
// Much later, possibly passing through various layers of the stack/maps/etc.
Item i = a;
c.find(i); // Will not compile if the find method takes an argument of type T
There is no benefit at all in forcing callers to downcast their Item reference to T specifically, when by definition you will be able to make the required method calls within find on an Item object, and can return an appropriate response based on the actual state of the object rather than the reference it is currently held in.
The key point is that the type of Container<? extends Item> means a container of something that extends Item, not anything that extends Item. Therefore it is possible that an object of type Item (the one being passed into the find method) may not be a compatible subclass of the something that extends Item. The compiler can not verify whether your code is correct, so it throws an error. The best you can do is allow a much broader parameter to find and restrict the return type:
public class Container<T> {
public void insert(T item) {
// insert...
}
public T find(Object o) {
// Lookup using a map or something return null if not found
}
}
I think the goal is misdirected here. You concede that your Container#insert() method can't work on a reference to wildcard-bound Container, but you expect that your Container#find() method can work. It's the same problem in both cases; you're trying to use covariance in both cases, which can't be enforced in Java against a wildcard like this.
Your original signature for Container#find() was fine. It met your specification. The latter one involving Searchable#find() is too relaxed; it allows one to search on any type of Item, rather than just types equivalent to or derived from the lower type T of the container. If the specification says that one should only be able to search for entries that are possibly in the container, and we don't know the specific type of the entries in the container, than we can't enforce that contract from a call site like Container#find().
Instead, try avoiding the wildcards like this:
private static <C extends Item, U extends C>
void useContainerOfSpecificItem(Container<C> c, C key1, U key2) {
c.find(key1);
c.find(key2);
}
There, you can see that find() accepts covariant types of keys, though, in this limited use, it's not actually necessary to distinguish type U from type C.
I could understand the error message, but still, this does not answer my question, which was:
Any ideas on how I can achieve this design goal in Java?
My current best solution is to use not one, but two generic parameters for the Collection class. The first designating what you can search for, and the other what you can insert.
If this is cumbersome, you use a superclass to capture the fact that you do not care about the type that "find" expects.
Still, I am not happy with this, and I hope a simpler solution exists.
public class Main {
public static class Searchable<R extends Item> {
public int find(R r) {
return r.hashCode();
}
}
public static class Container<T extends Item> extends Searchable<Item>{
public void insert(T t) {
System.out.println("Inserting " + t);
}
}
public static class Item {
// Nothing here
}
public static class ExtendedItem extends Item {
// And nothing here...
}
public static class Client {
public static void main(String[] args) {
useContainerOfItem();
useContainerWildCardOfItem(new Container<Item>());
Container<? extends Item> c;
c = new Container<Item>(); // OK. the type of c is a super type of Container<Item>
c = new Container<ExtendedItem>(); // OK. the type of c is a super type of Container<ExtendedItem>
useContainerWildCardOfItem(c);
}
private static void useContainerOfItem() {
Container<Item> c = new Container<Item>();
c.insert(new Item()); // OK. We can insert items
c.insert(new ExtendedItem()); // OK. We can insert items
c.find(new Item()); // OK. We can find items in here.
c.find(new ExtendedItem()); // OK. We can also find derived items.
}
private static void useContainerWildCardOfItem(Container<? extends Item> c) {
c.insert(new Item()); // Error: expected. We should not be able to insert an item!
c.insert(new ExtendedItem()); // Error: expected. We should not be able to insert anything!
c.find(new Item()); // No error, we should be able to find an Item
c.find(new ExtendedItem()); // No error, we should be able to find an ExtendedItem
}
}