ClassCastException vs instanceOf in Generic Collections - java

I have a class that implements Collection<E>.
When I check if my collection contains an item the interface's method give a parameter of object, when it's have to be an <E>
Do you think it's "normal" to write this code:
#Override
public boolean contains(Object o)
{
E item;
try
{
item=(E) o;
}
catch (ClassCastException e)
{
return false;
}
//check if contains "item"
}
I know that normally it's a terrible idea to check the type of an object with try,catch, but in a generic collection I can't check with instanceOf and I don't find a better solution.

From the javadoc it says:
Throws: ClassCastException - if the type of the specified element is incompatible with this collection (optional)
So it is perfectly acceptable to code it like this:
#Override
public boolean contains(Object o) {
T item = (T) o;
// ...
}
and if the cast fails a ClassCastException is thrown.
You certainly should not hide that exception and quietly return false - that could leave many potential bugs in the user's code.

If your collection class has E as a generic type parameter with no bounds, your check is useless -- the cast can't possibly fail, because the cast is completely unchecked. E, if it is unbounded, is erased to Object, and your cast will be item=(Object) o;, which cannot fail. It could lead to other failures in other places down the line, but it can't fail here, and if it fails in other places later your try-catch doesn't catch it.
The fact you can't use instanceof should have told you something -- the reason instanceof cannot be used is because it is a runtime check, which needs the class at runtime to check, and you don't have the class at runtime. Trying to have a cast fail is also a runtime check, so it does not improve your situation at all. Relying on a cast to fail only works in the same situations that instanceof works, so it NEVER makes sense to "use a cast because instanceof doesn't work".
When you write generic code, it is important to consider what the code looks like after type erasure. When you erase generic code into non-generic code (by adding casts in appropriate places), the code should work the same. If it is not possible to write the code as non-generic, then it cannot be written as generic either.
#Override
public boolean contains(Object o)
{
Object item;
try
{
item= o;
}
catch (ClassCastException e) // does this make sense?
{
return false;
}
//check if contains "item"
}

You are allowed to throw ClassCastException in this method, so You must not check type. Read javadoc of Collection interface.

Imho you should use equals / hashCode methods of parameter object to check if its present in your collection. Casting or instanceof is not required at all.

Related

Java instanceOf Class not comparing as expected [duplicate]

This question already has answers here:
How to check if a subclass is an instance of a class at runtime? [duplicate]
(7 answers)
Closed 5 years ago.
I have the following code,
public <T> T build(Object source, Class<T> destClass) {
if((Object)destClass instanceof TestDTO){
return (T) testBuilder.build((BlahDTO) source);
}
if((Object)destClass instanceof BestDTO) {
return (T) bestBuilder.build((BlahDTO) source);
}
return null;
}
I am trying to compare if the destClass if either of the type TestDTO or BestDTO and take the appropriate action. But the comparison fails even though the destClass is of the specified type. Am I missing something, also my alternate approach,
public <T> T build(Object source, Class<T> destClass) {
if(destClass.getSimpleName().equals(TestDTO.class.getSimpleName())){
return (T) testBuilder.build((BlahDTO) source);
}
if(destClass.getSimpleName().equals(BestDTO.class.getSimpleName())) {
return (T) bestBuilder.build((BlahDTO) source);
}
return null;
}
although this approach works, I find this code a bit dicey. It would be helpful if someone pointed out what I was doing wrong, or suggest an alternate approach. Thanks in advance!
instanceof checks to see if the left-hand operand is an instance of the right-hand operand. But your left-hand operand is a Class object, not an instance of that class. To use instanceof, you must have an instance of the class (something created via new TheClass).
As Thomas points out, if you really mean to be working with Class instances, you may want isAssignableFrom instead:
if (TestDTO.class.isAssignableFrom(destClass))
Side note: There's no purpose served by the (Object) cast on if((Object)destClass instanceof TestDTO). instanceof checks the object, not the kind of reference you have to it; casting is irrelevant to that check.

Type checking with generics

Here's an illustrational class:
class TypeChecker<T> {
boolean isGood(Object something) {
// won't compile
return (something instanceof T);
// maybe works, but oh so ugly!
try {
#SuppressWarnings("unchecked")
T tmp = ((T) something);
}catch(ClassCastException e) {
return false;
}
return true;
}
}
Is there any nice way to do this?
The particular purpose is a bit different than in the example, but the idea is the same - to check if a variable of type T (parameter) can hold certain object.
Use Class#isInstance.
class TypeChecker<T> {
private Class<T> ofType;
TypeChecker(Class<T> ofType) {
this.ofType = ofType;
}
boolean isGood(Object obj) {
return ofType.isInstance(obj);
}
}
Or just use the Class instead of making a wrapper object around it if all you need is the isInstance check.
There is not another way to perform run-time type checking dynamically. You must use a Class.
isInstance has the same semantics as instanceof (except that the left and right hand sides are flipped) so
"hello world" instanceof String
String.class.isInstance("hello world")
both are true.
Also, your 'maybe works' snippet, no that does not work. Generics are erased so unchecked casts do not happen at run-time. That is why they are unchecked. The ClassCastException will never throw. Using exceptions to determine logical flow is not good to begin with.

Invalid ClassCast Exception not raised when casting Object to generic type

I have a project, where i'm working with a lot of generics but also require typesafety.
Since the stacktrace is at about 200 calls, when the current error appears, im afraid that i can not deliver the complete sourcecode that is involved. I'll try to scratch it down to the problems i have spotted so far and deliver a brief example.
First, there are classes, holding generic values. Each generic implements Comparable. That might be a Long, a Boolean - or even custom Classes implementing this interface.
Each of such a class has a DatabaseID, wich is a enum-entry that contains a default value of a certain type. MOST the time this DatabaseId's Default Value is of the same type as the Generic-Class of the Holdingclass.
Something like this:
public enum DatabaseId{
A_LONG_VALUE(0L),
A_BOOLEAN_VALUE(false),
A_INTERVAL("");
}
Interval is such a custom class implementing the Comparable interface. But also Interval is an exception from the above mentioned rule. The Generic-Holding Class for "intervals" has a generic Type T of "Interval.class", while the DatabaseValue that persists the Interval stores it as a string. like [5,250] or [5] for discrete values.
Now, at some point, i need to "load" the value that is stored behind a Database id and inject it into the holding's class CurrentValue Attribute.
Since this is done on a "very" parent class of the whole hierarchy this is done in a generic way also:
public void initialize() {
Database db = Database.getInstance();
try {
this.setValue((T) db.get(this.getDatabaseId()));
} catch (Exception ex) {
Log.e(LOG_TAG, "Invalid cast while initializing Value Holder.", ex);
this.setValue(null);
}
}
For the mentioned Example, where a ValueHoler is holding Interval.class and the DatabaseId id delivering an String, this will obviously fail. At this point, i'm expecting an Exception, because i'm trying to cast an Object (db.get delivers Object) to the generic Type T (which is Interval in this example). The real type of the Database Entry however is String.
But: No Exception is thrown, so the setValue(null) is never executed. The Application contionues until a point, where ValueHolder.getCurrentvalue() is called and used to compare it with another value of the same Type i expect currentValue to be. (Interval in this case)
this.getCurrentValue().containsInterval(this.getRequiredValue());
At this point, JAVA notices that "CurrentValue" is a String, and throws an Exception:
java.lang.ClassCastException: java.lang.String cannot be cast to
my.namespace.Interval
The Actual problem
I can easily catch this szenario, like this:
public void initialize() {
Database db = Database.getInstance();
try {
if (this.getValueHolderValueType() == Interval.class){
//Interval has an constructor for the string represenatation of it
this.setValue((T) new Interval((String)db.get(getDatabaseId()));
}else{
this.setValue((T) db.get(this.getDatabaseId()));
}
} catch (Exception ex) {
Log.e(LOG_TAG, "Invalid cast while initializing valueHolder",ex);
this.setValue(null);
}
}
but if another developer comes along and implements a new Class extending Comparable he'll might be not be aware of the "manual" casting, and ran into the same troubles.
While writing this, I found a solution to notify the developer, like this:
-doing non-generic-casts first
-comparing both types
-raise notification if Generic cast is not possible.
if (this.getValueHolderValueType() == Interval.class){
this.setValue((T) new Interval((String)db.get(getDatabaseId())));
}else if (this.getValueHolderValueType() != this.getDatabaseId().getType()){
Log.e(LOG_TAG, "Invalid cast while initializing ValueHolder. DatabaseId delivers '"+this.getDatabaseId().getType()+"', but valueHolder expects '"+this.getValueHolderValueType()+"'. Maybe you are missing a non-generic-cast right here?");
}else{
this.setValue((T) db.get(this.getDatabaseId()));
}
So the only question that remains unanswered:
WHY is this.setValue((T) db.get(this.getDatabaseId())); NOT raising an exception, when T is of type Interval, DatabaseID's value is of type String and db.get is returning an Object?
WHY is the Exception thrown in the moment, when i try to Access the "wrong class" rather than when i'm doing the cast?
Because Java generics are implemented at the compiler level, which turns everything into Object (or other bound) and inserts the appropriate cast in the code that uses the object, rather than the code that simply passes it around.
Edit: To address your problem, you may wish to have an abstract method in your holder that returns the correct type it can store, and compare that with the type of the value returned from the database (either an == comparison or one of other kind), and throw your exception (or do something else) if the comparison fails.
Edit: For instance:
Object candidate = db.get(this.getDatabaseId());
boolean canBeStored = this.getStorageType().isInstance(candidate);
...
Edit: I see you already had similar logic in place. In order to make it work more OO, I'd suggest:
Object original = db.get(this.getDatabaseId());
T modified = this.adaptObjectToContainer(original);
...
protected T adaptObjectToContainer(Object original) {
if(this.getValueHolderValueType().isInstance(original)) {
return (T)original;
}
throw new ClassCastException(...);
}
// subclasses may do relevant conversions, throw an exception, etc
protected Interval adaptObjectToContainer(Object original) {
...
if(original instanceof String) {
return new Interval(original);
}
...
}
Ideally, to minimise code, there could be a utility class for each storage type which would be the responsible for the conversion.
As it was pointed in the previous answer, setValue(Object) succeeds because of type erasure.
If it makes sense for your application, you may try the following approach, where a reference to the expected class is mantained:
class Foo<T> {
private final Class<T> klass;
private T value;
Foo(Class<T> klass) {
this.klass=klass;
}
void setValue(Object obj) {
value=klass.cast(obj);
}
}
Then
Foo<Integer> foo = new Foo<Integer>(Integer.class);
foo.setValue("bar");//throws exception
See Class.cast(Object)

Check if an object belongs to a class in Java [duplicate]

This question already has answers here:
How to determine an object's class?
(13 answers)
Closed 9 years ago.
Is there an easy way to verify that an object belongs to a given class? For example, I could do
if(a.getClass() = (new MyClass()).getClass())
{
//do something
}
but this requires instantiating a new object on the fly each time, only to discard it. Is there a better way to check that "a" belongs to the class "MyClass"?
The instanceof keyword, as described by the other answers, is usually what you would want.
Keep in mind that instanceof will return true for superclasses as well.
If you want to see if an object is a direct instance of a class, you could compare the class. You can get the class object of an instance via getClass(). And you can statically access a specific class via ClassName.class.
So for example:
if (a.getClass() == X.class) {
// do something
}
In the above example, the condition is true if a is an instance of X, but not if a is an instance of a subclass of X.
In comparison:
if (a instanceof X) {
// do something
}
In the instanceof example, the condition is true if a is an instance of X, or if a is an instance of a subclass of X.
Most of the time, instanceof is right.
If you ever need to do this dynamically, you can use the following:
boolean isInstance(Object object, Class<?> type) {
return type.isInstance(object);
}
You can get an instance of java.lang.Class by calling the instance method Object::getClass on any object (returns the Class which that object is an instance of), or you can use class literals (for example, String.class, List.class, int[].class). There are other ways as well, through the reflection API (which Class itself is the entry point for).
Use the instanceof operator:
if(a instanceof MyClass)
{
//do something
}
I agree with the use of instanceof already mentioned.
An additional benefit of using instanceof is that when used with a null reference instanceof of will return false, while a.getClass() would throw a NullPointerException.
Try operator instanceof.
The usual way would be:
if (a instanceof A)
However, there are cases when you can't do this, such as when A in a generic argument.
Due to Java's type erasure, the following won't compile:
<A> boolean someMethod(Object a) {
if (a instanceof A)
...
}
and the following won't work (and will produce an unchecked cast warning):
<A> void someMethod(Object a) {
try {
A casted = (A)a;
} catch (ClassCastException e) {
...
}
}
You can't cast to A at runtime, because at runtime, A is essentially Object.
The solutions to such cases is to use a Class instead of the generic argument:
void someMethod(Object a, Class<A> aClass) {
if (aClass.isInstance(a)) {
A casted = aClass.cast(a);
...
}
}
You can then call the method as:
someMethod(myInstance, MyClass.class);
someMethod(myInstance, OtherClass.class);

Java Generics: Generic type defined as return type only

I'm looking at some GXT code for GWT and I ran across this use of Generics that I can't find another example of in the Java tutorials. The class name is com.extjs.gxt.ui.client.data.BaseModelData if you want to look at all of the code. Here are the important parts:
private RpcMap map;
public <X> X get(String property) {
if (allowNestedValues && NestedModelUtil.isNestedProperty(property)) {
return (X)NestedModelUtil.getNestedValue(this, property);
}
return map == null ? null : (X) map.get(property);
}
X is defined nowhere else in the class or anywhere in the hierarchy, and when I hit "go to declaration" in eclipse it just goes to the <X> in the public method signature.
I've tried to call this method with the following two examples to see what happens:
public Date getExpiredate() {
return get("expiredate");
}
public String getSubject() {
return get("subject");
}
They compile and show no errors or warnings. I would think at the very least I would have to do a cast to get this to work.
Does this mean that Generics allow a magic return value that can be anything and will just blow up at runtime? This seems counter to what generics are supposed to do. Can anyone explain this to me and possibly give me a link to some documentation that explains this a little better? I've went through Sun's 23 page pdf on generics and every example of a return value is defined either at the class level or is in one of the parameters passed in.
The method returns a type of whatever you expect it to be (<X> is defined in the method and is absolutely unbounded).
This is very, very dangerous as no provision is made that the return type actually matches the returned value.
The only advantage this has is that you don't have to cast the return value of such generic lookup methods that can return any type.
I'd say: use such constructs with care, because you lose pretty much all type-safety and gain only that you don't have to write an explicit cast at each call to get().
And yes: this pretty much is black magic that blows up at runtime and breaks the entire idea of what generics should achieve.
The type is declared on the method. That's that "<X>" means. The type is scoped then to just the method and is relevant to a particular call. The reason your test code compiles is that the compiler tries to determine the type and will complain only if it can't. There are cases where you have to be explicit.
For example, the declaration for Collections.emptySet() is
public static final <T> Set<T> emptySet()
In this case, the compiler can guess:
Set<String> s = Collections.emptySet();
But if it can't, you must type:
Collections.<String>emptySet();
I was just trying to figure out the same thing with a GXT class. Specifically I was trying to call a method with the signature of:
class Model {
public <X> X get(String property) { ... }
}
To call the above method from your code and have it cast X to a String I do the following:
public String myMethod(Data data) {
Model model = new Model(data);
return model.<String>get("status");
}
The above code will call the get method and tell it that the type being returned by X should be returned as a String.
In the case where the method is in the same class as you, I've found that I have to call it with a "this.". For example:
this.<String>get("status");
As others have said, this is rather sloppy and dangerous by the GXT team.
BaseModelData raises unchecked warnings when compiled, because it is unsafe. Used like this, your code will throw a ClassCastException at runtime, even though it doesn't have any warnings itself.
public String getExpireDate() {
return get("expiredate");
}
Interesting note, from RpcMap (GXT API 1.2)
get's header:
public java.lang.Object get(java.lang.Object key)
Having a generic parameter of <X> in there that's uninstantiated has the same effect, except you don't have to say "Object" all over the place. I agree with the other poster, this is sloppy and a bit dangerous.
Yes, this is dangerous. Normally, you'd protect this code like so:
<X> getProperty(String name, Class<X> clazz) {
X foo = (X) whatever(name);
assert clazz.isAssignableFrom(foo);
return foo;
}
String getString(String name) {
return getProperty(name, String.class);
}
int getInt(String name) {
return getProperty(name, Integer.class);
}

Categories