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.
Related
Suppose I have a library method like this (very abbreviated):
public static <V> Optional<V> doSomethingWith(Callable<V> callable) {
try {
return Optional.of(callable.call());
} catch (Exception ex) {
// Do something with ex
return Optional.empty();
}
}
And I want to something that doesn't return a value, like:
Library.</*What1*/>doSomethingWith(() -> {
foo();
return /*what2*/;
});
My first instinct for a generic method that doesn't return a value is making the type Void and returning null, however because the result gets wrapped in an Optional this would throw an exception.
What are reasonable placeholders for /*What1*/ and /*what2*/ that don't look totally random like Integer and 0?
[edit]
I'm trying to avoid Optional.ofNullable because empty is used here to indicate that callable.call() did not complete normally.
If you need a type hint for a generic parameter that will never be used you can use Void, the JDK does this too in some cases, e.g. when converting Runnable into CompletableFuture<T> it uses Void for T.
If you use Optional.ofNullable then you can just return null for what2, which is the only valid value for Void.
[edit] I'm trying to avoid Optional.ofNullable because empty is used here to indicate that callable.call() did not complete normally.
Then you're using the wrong tool for the job. CompletionStage or CompletableFuture has the right semantics.
I usually use Boolean.TRUE to mark success, but you could return Void.class as well. Both are cheap in the sense that not every return creates a new object to be discarded. Though Class<Void> is not just Void it may serve the purpose of labelling something as void just as well.
As already mentioned you could also create your own Result-class/-enum.
Or you could of course return Optional.<Void>nothing(), too. This would result in some Optional<Optional<Void>>, but also do the trick.
If you think all of the above is ugly, I fear that the API probably isn't to well tailored to your needs. Raise an issue/pull request or look for something else.
You could also create your own type similar to Void
public class Result {
public static final Result OK = new Result();
private Result(){}
}
and then return Result.OK.
You can also enhance this type to represent also errors, if you need.
But maybe using java Void is preferable if you don't need anything special.
Use Void for the return type, which is the logical choice for "nothing", but actually return an instance of Void.
Although the javadoc for Void says it's:
...an uninstantiable placeholder class...
You can nevertheless instantiate it:
try {
Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
return c.newInstance();
} catch (Exception perfunctory) {
return null; // won't happen
}
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.
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)
I have the following method:
public static String getServiceUri(Class<?> c) {
// I'd like to check which type the parameter is...
if(c.getClass().equals(MyClass.class)){
do stuff 1
} else {
do stuff 2
}
}
Invoke method:
getServiceUri(MyClass.class);
On getServiceUri I want to call a WebService based on the type of a ServiceClass.
I know that equals will compare objects instance, but in this case I'm trying to discover the type of object.
Anyone know how I can compare using this kind of approach?
instanceof operator is the best choice..
you can do something like this
if(c instanceof MyClass){
//do your stuff
}
public static String getServiceUri(Class<?> classParam) {
if(classParam instanceof MyClass){
}
}
This is WRONG. It does not even compile because classParam needs to be an actual instance(object) to use the instanceof operator: hence the name.
If you want to know if the classParam is exactly equal to MyClass.class:
public static String getServiceUri(Class<?> c) {
if(classParam == MyClass.class){
}
}
However, if you want to check the entire hierarchy of classParam against MyClass then you can do classParam.isAssignableFrom(MyClass.class)
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);