A NavigableSet<String> does not match Collection<Object> in method argument - java

I have a method which takes a Collection<Object> where the Object can be a String or CustomClass. It then takes each element of the collection and passes it to a method with an argument of Object like so:
public void foo(Collection<Object> c) {
for(Object o : c)
bar(o);
}
public void bar(Object o) {
if(o instanceof String || o instanceof CustomClass) {
...
}
}
bar works fine when I pass it a String or CustomClass, but when I try to pass a NavigableSet<String> to foo I get cannot find symbol; symbol : method foo(java.util.NavigableSet<java.lang.String>).
However if I change the the argument type in foo to Collection<String> it works fine, but this means I need to make a new foo(Collection<CustomClass>) method which will involve repeating code. Is there a way around this?

Collection<String> is not a subtype of Collection<Object>, therefore the compiler doesn't find any compatible methods. Put
public <T> void foo(Collection<T> c) {
for (T o : c) bar(o);
}

The inheritance relationship between T<A> and T<B> is is called "generic covariance".
It is not as simple as, if A inherits from B, then T<A> inherits from T<B>, because the type parameter may be "in" or "out" (as C# would put it).
See for example http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html
or java generics covariance
or http://etymon.blogspot.co.uk/2007/02/java-generics-and-covariance-and.html
Marko's suggestion is the simplest fix for your problem.

Related

How to handle generics type in return type in Collection

I have a case where I have to return a list of two different types based on a condition. But it always fails
public class App {
public static void main(String[] args) {
System.out.println(getData(true, Integer.class));
}
public static <E> List<E> getData(Boolean isLe, Class<E> clazz) {
return isLe ? Arrays.asList(20) : Arrays.asList("test");
}
}
Error:
Error:(18, 36) java: incompatible types: bad type in conditional expression
inference variable T has incompatible bounds
equality constraints: E
lower bounds: java.lang.Integer
How can this be resolved?
You don't need to provide the class to return a generic List with a specific type but you need to use inference of the target if you want that it returns the required type :
#SuppressWarnings("unchecked")
public static <T> List<T> getData(Boolean isLe) {
return isLe ? (List<T>)Arrays.asList(20) : (List<T>)Arrays.asList("test");
}
And use it :
List<Integer> data = getData(true);
or :
System.out.println(getData(true);
But this code also defeats the generic safety as the client may provide an incompatible type in the target :
List<Integer> data = getData(false);
// you will get a List of String that is stored in a List of Integer
So your requirement seems to be inconsistent.
Either the client should decide of the generic type of the List or the method that you call should decide that. But not both.
Your logic would make sense only if the types derived from a common base class. And in this case using as generic a List of this base class would be enough.
For example :
public static List<Number> getData(Boolean isLe) {
return isLe ? Arrays.asList(20) : Arrays.asList(15F);
}
That you could call :
List<Number> data = getData(false);
In your case, the method may return numbers or String, so you should use their base class as generic type : Object :
public static List<Object> getData(Boolean isLe) {
return isLe ? Arrays.asList(20) : Arrays.asList(15F);
}
And invoke it :
List<Object> data = getData(false);
But now, what is the advantage to use a generic list that is typed with Object ?
No one as you will finish probably by adding downcast in the client code to use specific methods on the elements of the list.
The Boolean parameter is rather obscure, after all, you already have the clazz parameter for describing the expected result better than a boolean and why Boolean instead of boolean? Do you want to support null values for this parameter?
You can implement the method as
public static <E> List<E> getData(Class<E> clazz) {
if(clazz == Integer.class) return Arrays.asList(clazz.cast(20));
if(clazz == String.class) return Arrays.asList(clazz.cast("test"));
throw new IllegalArgumentException(clazz+" is neither String nor Integer");
}
and use it like
List<Integer> intList = getData(Integer.class);
System.out.println(intList);
List<String> strList = getData(String.class);
System.out.println(strList);
But generally, I do not recommend such a design. After all, while it’s better than having to guess the meaning of the boolean parameter, the signature still doesn’t allow a caller to recognize, which type arguments are supported.

Java Undefined Object

I got an arraylist and a method to add an object to the arraylist. Currently im using overloaded methods to differentiate between different kinds of object. Is there a way to use an undefined object as a parameter for the method and differentiate inside of the method what kind of an object it is?
By "undefined object as a parameter", I assume you mean that you're looking to write a function that doesn't specify the type of the object in the function declaration, allowing you to only have one function.
This can be done with generics.
Instead of:
static void func(String str)
{
System.out.println("The string is: "+str);
}
static void func(Integer integer)
{
System.out.println("The integer is: "+integer);
}
you can have:
static <T> void func(T value)
{
if (value instanceof Integer)
System.out.println("The integer is: "+value);
else if (value instanceof String)
System.out.println("The string is: "+value);
else
System.out.println("Type not supported!! - "+value.getClass());
}
Test:
func("abc"); // The string is: abc
func(3); // The integer is: 3
func(3.0); // Type not supported!! - class java.lang.Double
See Java generics for more information.
One way you can do it is pass two parameters. First parameter is the Object you need to pass and second parameter is the indicator of which type of Object you are passing.
public void TestFunc(Object obj1, String type){}
Of course, there can be better ways than using a String, we can use Enums and some other mechanism. You can also use InstanceOf to differentiate if you don't want to pass additional parameter.
By "undefined object" I assume you mean null. You can cast null to a specific type of object and the compiler will know which overloaded method to bind to the call:
public void method(String s) { . . . }
public void method(Integer s) { . . . }
public void caller() {
method((String) null);
method((Integer) null);
}
If you have an object of undefined type, you can use instanceof operator to test what type it is, or getClass() to obtain the class object itself. If you have a null value of unknown type, there's not much you can do other than redefining your method signature to accept an additional argument of type Class.
However, if the comment by Dukeling is accurate and by "undefined object" you mean "an object of unknown type", you should look into using Java generics. Generics let you write a single method that works with a range of object types.
public <T> void method(T arg) { . . . }
public void caller() {
method("String"); // String arg
method(0); // Integer arg
}
Start with the Java generics tutorial for more information.

How to call a polymorphic function from an agnostic function?

I have a method foo
void foo (String x) { ... }
void foo (Integer x) { ... }
and I want to call it from a method which does not care about the argument:
void bar (Iterable i) {
...
for (Object x : i) foo(x); // this is the only time i is used
...
}
the code above complains that that foo(Object) is not defined and when I add
void foo (Object x) { throw new Exception; }
then bar(Iterable<String>) calls that instead of foo(String) and throws the exception.
How do I avoid having two textually identical definitions of bar(Iterable<String>) and bar(Iterable<Integer>)?
I thought I would be able to get away with something like
<T> void bar (Iterable<T> i) {
...
for (T x : i) foo(x); // this is the only time i is used
...
}
but then I get cannot find foo(T) error.
The problem you are facing is that overloaded methods are bound at compile time. In your example, the compiler tries to figure out which of the foo() methods to call. However, the strongest static type of x in your example is Object, and there is not method foo(Object), so the compiler says it can't call the appropriate method.
If you add the foo(Object) method, no matter what the actual runtime type of x is, you will always call the foo(Object) method.
This problem extends to using generics. Since T can be any type, you must have a generic method foo(T) or your code will not compile. However, if you add that method, you lose the ability to have these methods discern between the different argument types, because only foo(T) will be called.
The only way to work around this is by doing a case by case check and cast like the other answers proposed. Unless the argument types are classes you define and they can all implement a common interface. Then you can do something like:
interface ArgumentType {
void callback(FooClass c);
}
class YourClassA implements ArgumentType {
void callback( FooClass c ) {
c.foo( this );
}
}
FooClass would still have to have a foo() method for every implementing class of ArgumentType, but this way you can have your selection by type agnostic.
Think of it this way: which version of foo should be called if x is an Object?
That's the problem faced by the JVM.
If you want a truly polymorphic method, then you need to explicitly write one. Such a method could then inspect the Object through introspection to see what it's actual class type is and call the appropriate method after that.
Or, you could take a close look at what foo does. Is it only calling methods defined by Object? If so, just create a void foo(Object x) method that does the necessaries.
The trouble is you are trying to find foo(Object x) and while String and Integer are both Objects, not all Objects are either String or Integer, and java doesn't narrowcast to the right class.
I would perhaps suggest creating a method like:
void foo(Object o){
if ( o instanceof String){
String s = (String) o;
//Deal with s
} else if ( o instanceof Integer){
Integer i = (Integer) o;
//Deal with i
}
}
Also, if you are using generics anyway, you shouldn't be passing a raw iterator in bar

What does Java's type parameter wildcard really mean? What's the real difference between Foo and Foo<?>?

For a generic interface:
public interface Foo<T> {
void f(T t);
}
The difference between the two fields:
public class Bar {
Foo foo1;
Foo<?> foo2;
}
Is that foo2 is a generic Type and foois not. Since ? is a wildcard (which I think means any type) and every type is a sub-type of Object, then I wold expect Foo<?> and Foo<Object> to semantically and syntactically equivalent.
However, check out the following:
public class Puzzler {
void f() {
Integer i = null;
Foo<?> foo1 = null;
foo1.foo(i); // ERROR
Foo foo2 = null;
foo2.foo(i); // OKAY
Foo<Integer> foo3 = null;
foo3.foo(i); // OKAY
Foo<Object> foo4 = null;
foo4.foo(i); // OKAY
}
private interface Foo<T> {
void foo(T t);
}
}
So Foo<?> and Foo<Object> are not the same syntactically.
What's going on here? I'm pretty stuck in trying to understand this.
Foo<?> is semantically the same as Foo<? extends Object>: it is a Foo with type parameter of something specific, but the only thing known about "something" is that it is some subclass of Object (which isn't saying too much, since all classes are subclasses of Object). Foo<Object>, on the other hand, is a Foo with type parameter specifically Object. While everything is assignment-compatible with Object, not everything will be assignment-compatible with ? where ? extends Object.
Here's an example of why Foo<?> should generate an error:
public class StringFoo implements Foo<String> {
void foo(String t) { . . . }
}
Now change your example to this:
Foo<?> foo1 = new StringFoo();
Since i is an Integer, there's no way that the compiler should allow foo1.foo(i) to compile.
Note that
Foo<Object> foo4 = new StringFoo();
will also not compile according to the rules for matching parameterized types since Object and String are provably distinct types.
Foo (without type parameter at all—a raw type) should usually be considered a programming error. According to the Java Language Specification (§4.8), however, the compiler accepts such code in order to not break non-generic, legacy code.
Because of type erasure, none of this makes any difference to generated the byte code. That is, the only differences between these are at compile time.
Consider these types:
List<Object>
List<CharSequence>
List<String>
Even though String is a subtype of CharSequence which is a subtype of Object, these List types do not have any subtype-supertype relationships. (Curiously, String[] is a subtype of CharSequence[] which is a subtype of Object[], but that's for historical reasons.)
Suppose we want to write a method which prints a List. If we do
void print(List<Object> list) {...}
this will not be able to print a List<String> (without hacks), since a List<String> is not a List<Object>. But with wildcards, we can write
void print(List<?> list) {...}
and pass it any List.
Wildcards can have upper and lower bounds for added flexibility. Say we want to print a list which contains only CharSequences. If we do
void print(List<CharSequence> list) {...}
then we encounter the same problem -- we can only pass it a List<CharSequence>, and our List<String> is not a List<CharSequence>. But if we instead do
void print(List<? extends CharSequence> list) {...}
Then we can pass this a List<String>, and a List<StringBuilder>, and so forth.
Well, due to the type erasure, anything generics-related is compile-time only; I guess that's what you are calling syntactical.
I think your initial assessment is correct and real difference is that makes it a generic-typed variable and plain Foo doesn't.
Object is the supertype of all types in java. However, Foo is not the supertype of all Foo. The supertype of all Foo is Foo. see http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html for more details.
The wildcard in Foo<?> indicates that within the current scope, you don't know or care what type of 'Foo' you have.
Foo<?> and Foo<? extends Object> are the same (the first is shorthand for the other). Foo<Object> is different.
A concrete example:
You can assign any sort of List to List<?>
e.g.
List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<Object>();
List<?> list3 = new ArrayList<CharSequence>();
If you have a List<?> you can call size() because you don't need to know what type of list it is to find out its size. And you can call get(i) because we know that the list contains some sort of Object, so the compiler will treat it as if get returns and Object.
But you can't call add(o) because you don't know (and the compiler doesn't know) what sort of list you're dealing with.
In our example above you wouldn't want to allow list1.add(new Object()); because that's supposed to be a list of Strings
The reason for wildcards is so you can do things like this:
public static boolean containsNull(List<?> list)
{
for(Object o : list )
{
if( o == null ) return true;
}
return false;
}
That code can work on any sort of list that you want, a List<String>, List<Object>, List<Integer>, etc.
If the signature was public static boolean containsNull(List<Object> list) then you could only pass List<Object> to it, List<String> wouldn't work.

Why does the compiler state no unique maximal instance exists?

I have the following classes:
public class Obj<T> extends BaseModel {
public static final String OBJECT = "object";
public Obj(T object) {
setObject(object);
}
public T getObject() {
return get(OBJECT);
}
public void setObject(T object) {
set(OBJECT, object);
}
}
And...
/** This is a 3rd party library class **/
public class BaseModel implements ModelData, Serializable {
//...members and stuff...
#SuppressWarnings({"unchecked", "rawtypes"})
public <X> X get(String property) {
X obj = null;
if (start > -1 && end > -1) {
Object o = map.get(property.substring(0, start));
String p = property.substring(start + 1, end);
if (o instanceof Object[]) {
obj = (X) ((Object[]) o)[Integer.valueOf(p)];
} else if (o instanceof List) {
obj = (X) ((List) o).get(Integer.valueOf(p));
} else if (o instanceof Map) {
obj = (X) ((Map) o).get(p);
}
} else {
obj = (X) map.get(property);
}
return obj;
}
}
When I compile, I get the following error.
type parameters of <X>X cannot be determined; no unique maximal instance exists for type variable X with upper bounds T,java.lang.Object -> getObject()
It doesn't happen in Eclipse, which, as far as I can tell, is using the same JDK as my Ant build. I've seen the SO thread about the Sun compiler issue, but that seemed to be for static methods declaring types on the fly.
Why am I getting this error, and more importantly, how do I get around it?
So far the only why I've found is to cast in my method like this:
#SuppressWarnings({"unchecked"})
public T getObject() {
return (T) get(OBJECT); //yuck
}
Telling my I'm on crack and this is the proper way is acceptable.
This is dummy bug that has been fixed in Java SE 7.
It does not compile because your code expects too much from generics -> i.e., the < X > X part in:
public <X> X get(String property) { ... }
In the following code:
public T getObject() {
return get(OBJECT);
}
you have to keep in mind that generics are always "unfolded" before the compiler actually starts to compile the Java code. It is a pre-processing step.
In your case, the compiler does not know what to use to replace X at compile time. The compiler needs to be sure about the type of X, because it needs to check it against T to validate the code. Hence the error...
A solution to your issue is to replace < X > X with Object:
public Object get(String property) { ... }
and add a cast in:
public T getObject() {
return (T) get(OBJECT);
}
Your will get an unchecked-cast warning at compile time, but your code will compile (so yes your workaround is valid).
Method type parameters are most often implicitly inferred from the arguments to that method. Note, however, get has no explicit relationship between the argument and the type parameter:
public <X> X get(String property)
Type inference is the usual path, but methods can also be invoked with explicit type arguments, just like classes. The format roughly follows that of the declaration, so inside of Obj you could have
public T getObject() {
return super.<T>get(OBJECT);
}
You could also just be direct and use <Object>, but you'd still have to use that unchecked cast to get it back to T. Note the explicit argument needs a qualifier, usually the instance name of the class. Since your example used a method of the superclass, its reference is implicit through super.
This doesn't solve the underlying problem of applying a generic method (<X> X get) inside of a non-generic class (BaseModel). Note the code in the library makes forcible type casts to the type argument. This style is indeed one of the solutions to back-porting generic features into non-generic Java code. It looks like they're trying to hide this from the library users, but since they didn't genericize the class the type can't be inferred from the instance (i.e. you really want to have Obj<T> extends BaseModel<T>).
[EDIT: corrected and explained explicit method type argument]
I just encountered a similar issue with a project using Apache Pivot. The client code was riddled with lines like:
boolean foo = org.apache.pivot.json.JSON.get(item, "foo");
The code would compile in Eclipse, but not using Maven or javac from the command line. It appears to be Bug 6302954, but I still see it after updating to the latest JDK.
As the JSON class is provided by Pivot, it's not something I could modify within my own source tree (forking the library is not an option on this project)
The solution that worked for me came from the first reply in the bug report, changing the code to read:
boolean foo = org.apache.pivot.json.JSON.<Boolean>get(item, "foo");

Categories

Resources