Compare object type - java

I don't know how to perform type checking on newEntry, I want to make sure that it is of type MyTable (without creating an object of MyTable).
public static boolean add(String table, Object newEntry)
{
boolean result;
if (table.equals("MyTable") && newEntry.getClass() == MyTable.getClass())
{
...
}
}
My problem is:
newEntry.getClass() == MyTable.getClass().
Note: MyTable is a class name, not an object.

Basically what you want is:
isAssignableFrom
Take a look at: http://www.ralfebert.de/blog/java/isassignablefrom/
So, in your case, you want:
MyTable.class.isAssignableFrom(newEntry.getClass())

Use instanceof operator .. Refer to the JLS for more documentation
Check this famous answer What is the difference between instanceof and Class.isAssignableFrom(...)?

instanceof is your friend:
if (table.equals("MyTable") && newEntry instanceof MyTable)
It is actually a shorthand for the isAssignableFrom method, but it's much easier to type :)

Compare with instanceof.
if (newEntry instanceof MyTable) {
// do something
}
In this example, the condition is true if newEntry is an instance of MyTable, or if newEntry is an instance of a superclass of MyTable.
Change your statement to this to make it work properly:
if (table.equals("MyTable") && newEntry instanceof MyTable)
You could also use isAssignableFrom() to compare them. The reason you might want to do this is because with instanceof, you have to know the class you are comparing before you compile your program. With isAssignableFrom(), you can change the class you are comparing to during run-time.
if (table.equals("MyTable") && MyTable.class.isAssignableFrom(newEntry.getClass()))

You can use MyTable.class to retrieve the class name.

Related

java.util.Objects.isNull vs object == null

As you know, java.util.Objects is
This class consists of static utility methods for operating on objects.
One of such methods is Objects.isNull().
My understanding is that Objects.isNull() would remove the chance of accidentally assigning a null value to object by omitting the second =.
However, the API Note states:
This method exists to be used as a Predicate, filter(Objects::isNull)
Would there be any reason/circumstance for which I should use object == null over Objects.isNull() in an if statement?
Should Objects.isNull() be confined to Predicates exclusively?
should use object == null over Objects.isNull() in a if statement?
If you look at the source code of IsNull method,
/* Returns true if the provided reference is null otherwise returns false.*/
public static boolean isNull(Object obj) {
return obj == null;
}
It is the same. There is no difference. So you can use it safely.
Objects.isNull is intended for use within Java 8 lambda filtering.
It's much easier and clearer to write:
.stream().filter(Objects::isNull)
than to write:
.stream().filter(x -> x == null).
Within an if statement, however, either will work. The use of == null is probably easier to read but in the end it will boil down to a style preference.
Look at the source:
public static boolean isNull(Object obj) {
return obj == null;
}
To check for null values, you can use:
Objects.isNull(myObject)
null == myObject // avoids assigning by typo
myObject == null // risk of typo
The fact that Objects.isNull is meant for Predicates does not prevent you from using it as above.
Would there be any reason/circumstance for which I should use object == null over Objects.isNull() in a if statement?
Yes, one reason is to keep the code simple. Within if statement object == null is clear and well known. It can not lead to any misbehavior if for example there is a typo.
My understanding is that Objects.isNull() would remove the chance of accidentally assigning a null value to object by omitting the second =.
If there is an if (object = null) {} with omitted = it will not compile or it will generate warning in case of Boolean object! Actually there is no reason to use Objects.isNull(object) over object == null within if statement. Here are the two variants side by side:
if (object == null) {
}
if (Objects.isNull(object)) {
}
Should Objects.isNull() be confined to Predicates exclusively?
It could be said yes, it is confined to Predicates exclusively, although there is no technical hurdle to use the Objects.isNull() everywhere.
From the public static boolean isNull(Object obj) method's javadoc:
#apiNoteThis method exists to be used as a java.util.function.Predicate, filter(Objects::isNull)
So if you use the method as not a predicate you are actually using a more complex and cumbersome expression compared to the simple object == null.
Here is a snippet to compare the benefit of Objects.isNull(object)
List<String> list = Arrays.asList("a", "b", null, "c", null);
// As ready-made predicate
long countNullsWithPredicate = list.stream().filter(Objects::isNull).count();
// Lambda
long countNullsWithLambda = list.stream().filter(object -> object == null).count();
// Reimplement the Objects::isNull predicate
long countNullsWithAnonymous = list.stream().filter(new Predicate<Object>() {
#Override
public boolean test(Object obj) {
return obj == null;
}
}).count();
Semantically there is no difference but for readability I prefer the following over whatever == null:
import static java.util.Objects.isNull;
// Other stuff...
if(isNull(whatever)) {
}

How to typesafe check equality of booleans?

public class ComplexObject {
private boolean isA, isB;
}
//custom comparator
public boolean checkComplexObject(ComplexObject o1, ComplexObject o2) {
return o1.getIsA() == o2.getIsB();
}
Now when I change the data type in ComplexObject from boolean to String for example, the comparator will not break, nor will I notice that in future I would compare Strings instead of booleans and thus get different results.
Question: how could I compare the boolean properties typesafe, so that I get compilation error when I change the datatype of the fields?
One very simple thing you can do is put in a redundant cast:
return (boolean)o1.getIsA() == (boolean)o2.getIsB();
You can also define a method that only accepts boolean:
static boolean booleanEquals(boolean a, boolean b) {
return a == b;
}
Then call booleanEquals instead of using ==.
As a side note, this programming seems a bit overly defensive to me.
There are a few things you can do, but all of them will make your code less readable, and therefore I would advise against them.
For example :
return o1.getIsA() ^ o2.getIsB() == false;
or
return (o1.getIsA() && o2.getIsB()) || (!o1.getIsA() && !o2.getIsB());
You can use XOR for that:
return o1.getIsA() ^ o2.getIsB();
The better question is, why would you do that?
If you refactor (well, change heavily) your attributes from boolean to String you should always check the affected code. If you want code workarounds for a common practice (double checking), you're may introduce overly complicated code in your whole application.
If you're aware of that problem, why dont you put a comment directly on your affected class attributes, that it may be compared by ==. If you want or another dev wants to change it's type later on, they will be warned.

Standard approach to assign default value in Java

Often I invoke alien methods which might return a null value. In order to avoid simple null checks like
if (myVariable != null) {
// do something
}
I sometimes assign a default value, like this:
myVariable = (myVariable == null) ? defaultValue : myVariable;
This seems a little bit redundant in Ruby for instance, there is the ||= operator
I am not asking for such an operator, but my standard approach with the ternary operator seems a little bit redundant or maybe also confusing?
What better ways are there?
Try this:
if (myVariable == null) {
myVariable = defaultValue;
}
If the alien method maybe return null value, it should note about null return value in method's Java docs. The client uses that alien method must check, but no way, the return value.
The simple way to do this:
retVal = alienMethod();
if (retVal == null) {
retVal = defaultVal;
}
If you still want to avoid checking null value, the method that return the value must be in responsible for return default value. But what is your default value? Depend on your return type, you can create a dummy class to represent your default value instead of returning null value.
There are no better/shorter/nicer ways to do it....
There was talk about introducing a '?' operator for null values in Java 7, but the concept got shifted out of the release.... maybe for Java 8 ?
https://blogs.oracle.com/darcy/entry/project_coin_final_five
http://viralpatel.net/blogs/2009/10/null-safe-type-java-7-nullpointerexception.html
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html
In general, there is no "elegant" way. If the variable is a field of your class, you can do it in the setter or getter. But proper javadocs (which I don't show below!) are important to explain what happens to nulls. e.g.
public void setFoo(Foo foo) {
this.foo = foo != null ? foo : DEFAULT_FOO;
}
public Foo getFoo() {
return foo != null ? foo : DEFAULT_FOO;
}
You can wrap the assigning of a default value into a small utility function and put it in a helper class. For variables of type String, this would look like this:
public static String unNull(String val,String defVal) {
return (val==null ? defVal : val);
}
Then, in your code you can just write
myVariable = unNull(alienMethod(),defaultValue);
Using a static import, you can do without prefixing the static method's name with the class name.
You can also make a generic method to handle this (to template the type of both arguments and the return type), but I'm not sure it would work without an additional parameter of type Class.
There is finally a better way to do it: Optional in Java 8. Instead of
Foo myVariable = bar();
myVariable = (myVariable == null) ? defaultValue : myVariable;
where bar() may return null, now you do
Foo myVariable = Optional.ofNullable(bar()).orElse(defaultValue).get()

How should this instanceof condition look like?

I have a list of nodes. This nodes are a data class I defined by myself. Each node has a data field of the type Object. Now I want to find the node in a list of nodes that has the parameter object in the data field. I wrote this method, because I wanted to first compare if the two objects (the parameter and the object in the data field) are of the same type:
public Node getnNodeByData(Object obj) {
for (Node node : nodes) {
if (node.getData() instanceof obj.getClass()) {
}
}
}
Unfortunately this condition does not work:
Incompatible operand types boolean and Class<capture#1-of ? extends Graph>
I don't really know why this is a problem. How can I make this working?
No, you need to use Class.isInstance(Object). The instanceof keyword does not expect an object of type Class, but only the name of the class directly -- but Class.isInstance is basically analogous.
No, that is not possible like that. You should use isAssignableFrom() or isInstance(). The difference between the two methods is that isInstance(null) will return false and isAssignableFrom(null) will give true.
[object] instanceof [class]
should be translated to this:
[class].class.isAssignableFrom(object.getClass());
Example:
Integer i = 4;
boolean b = i instanceof Number;
boolean k = Number.class.isAssignableFrom(i.getClass());
b and k are equivalent.

In a Java method that takes an Object argument, how can you access fields that only exist for instances of specific classes?

-- Yes, this is a question asking for help regarding something that was assigned as homework. No, this is not me asking you to do my homework for me. The deadline was a half an hour ago; I literally can't change my submission. You'll just have to take my word for it. Moving on...
I know that testing for the type of objects is supposed to be unnecessary. When I was looking for details about 'instanceof', I found a half dozen threads where people responded only to tell the original poster that they were making a mistake if they had to test to find out what kind of object they were dealing with before processing it. Yes, I know, I would love to follow the conventions. Unfortunately, my professor asked for us to override the equals method of a class we defined, and specifically required an Object type parameter. If you see my code, you'll probably understand better:
public boolean equals(Course other){
if(!(other instanceof Course)){
return false;
} else if(other.name==this.name && other.days==this.days &&
other.start==this.start && other.end==this.end){
return true;
}
return false;
}
You can probably understand where I'm going with this. The 'other' parameter should be an Object type, but the program has a fit if I leave it as an Object and use the name / days / start / end fields. If I change it to Course, of course it works (no pun intended), but that would be a completely different method. The desired behavior is for all objects other than Course instances to make the method return false, and additionally, for mismatched data between Course instances to make it return false.
I'm sorry to all of you who know Java well enough to be frustrated by seeing questions like these.
If you want to override the "equals" method, you should use Object as a parameter, and thus you have to check for the object's type. Usually your own implementation would look like this:
#Override
public boolean equals(Object obj) {
if (obj == this)
return true; // object's references are identical
else if (!(obj instanceof Course))
return false;
Course that = (Course) obj;
return (this.name.equals(that.name)) && (this.days == that.days)
&& (this.start.equals(that.start)) && (this.end.equals(that.end));
}
Of course you should override "hashCode" as well, using the same significant fields.
Instead, you overloaded the method with your own parameter of type Course. So if you call myobject.equals(anotherObject) and anotherObject is not of type Course, your "equals" method will never be called, instead the Object#equals method will be called, which does only the following: return this == obj.
The reason why overloading the "equals" method is not enough is the necessity to overload "hashCode" as well, which takes no parameters and thus cannot be overloaded.
If you write your own implementation of boolean equals(Object), you must also implement int hashCode()
Both methods should use the same significant fields for "hashCode" and "equals".
If a.equals(b) == true than the following must be also true: a.hashCode() == b.hashCode()
Also if a.hashCode() != b.hashCode() then a.equals(b) == false
The last point is the main reason why you should not just overload "equals" with your own type:
Course c1 = new Course("myname");
Course c2 = new Course("myname");
c1.equals(c2); // true
c1.hashCode() == c2.hashCode(); // false
You can cast Object as Course:
Course course = (Course)object;
Then do all the comparisons on the course object. Obviously, still do the instanceof check before casting to avoid a ClassCastException.
You're trying to cast it:
Cource c = (Course)other;
Your code :
public boolean equals(Course other){
if(!(other instanceof Course)){ <-- other can only be Course here
return false;
} else if(other.name==this.name && other.days==this.days &&
other.start==this.start && other.end==this.end){
return true;
}
return false;
}
Correct code :
public boolean equals(Object other){
if(!(other instanceof Course)){
return false;
} else{
Course c = (Course) other;
if(c.name==this.name && c.days==this.days &&
c.start==this.start && c.end==this.end){
return true;
}
}
}
return false;
}

Categories

Resources