You can simply use Apache Commons Lang:
result = ObjectUtils.compare(firstComparable, secondComparable)
Answer from Dag on Stack OverflowYou can simply use Apache Commons Lang:
result = ObjectUtils.compare(firstComparable, secondComparable)
Using Java 8:
private static Comparator<String> nullSafeStringComparator = Comparator
.nullsFirst(String::compareToIgnoreCase);
private static Comparator<Metadata> metadataComparator = Comparator
.comparing(Metadata::getName, nullSafeStringComparator)
.thenComparing(Metadata::getValue, nullSafeStringComparator);
public int compareTo(Metadata that) {
return metadataComparator.compare(this, that);
}
I've already discovered that comparing a generic type requires you to use an int to restore the value of compareTo, but if I'm trying to check if T value == Null, java throws an error stating that the compareTo (null) method is undefined for type T.
the code I have so far is
int cmp; if(cmp = tree.get(index).compareTo(null) == 0)
to check if the value at the index of tree == null.
Thanks in advance :)
edit: well, I actually just fixed it by deleting cmp XD
I try to avoid casts whenever possible, so I'd rather use the following, which also looks nicer in my opinion:
Integer.valueOf(8).equals(m.get("null"))
The == operator doesn't compare values, but references.
You should use the .equals() method, instead, applied to the Integer variable (for which you are sure that is not null and NPE won't be thrown):
Integer eight = 8; //autoboxed
System.out.println(eight.equals(m.get("null")));
This will print false even the m.get("null") returns null.
I think you want:
if (count1 != null && count2 != null && count1 > count2)
do something;
else
do something else;
Java will auto un-box the Integer objects to int primitive values to make the mathematical > comparison.
Is there a way to implement that if count1 or count2 is a null value, return false
if (count1 == null || count2 == null) return false;
if (count1 > count2)
doSomething();
else
doSomethingElse();
When I type
string1 == string2
IntelliJ tells me to switch to equals(), which it says is null-safe.
But is == operator not null-safe?
I tried null == "abc", "abc" == null, null == null, but they consistently gave me right false false true.
What am I missing here?
The Short Answer
The key point is this:
==between two reference types is always reference comparison- More often than not, e.g. with
IntegerandString, you'd want to useequalsinstead
- More often than not, e.g. with
==between a reference type and a numeric primitive type is always numeric comparison- The reference type will be subjected to unboxing conversion
- Unboxing
nullalways throwsNullPointerException
- While Java has many special treatments for
String, it is in fact NOT a primitive type
The above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.
The Long Answer
Here are the relevant JLS sections:
JLS 15.21.3 Reference Equality Operators
==and!=If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
This explains the following:
Integer i = null;
String str = null;
if (i == null) { // Nothing happens
}
if (str == null) { // Nothing happens
}
if (str == "0") { // Nothing happens
}
Both operands are reference types, and that's why the == is reference equality comparison.
This also explains the following:
System.out.println(new Integer(0) == new Integer(0)); // "false"
System.out.println("X" == "x".toUpperCase()); // "false"
For == to be numerical equality, at least one of the operand must be a numeric type:
JLS 15.21.1 Numerical Equality Operators
==and!=If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible to numeric type, binary numeric promotion is performed on the operands. If the promoted type of the operands is
intorlong, then an integer equality test is performed; if the promoted type isfloat ordouble`, then a floating-point equality test is performed.Note that binary numeric promotion performs value set conversion and unboxing conversion.
This explains:
Integer i = null;
if (i == 0) { //NullPointerException
}
Here's an excerpt from Effective Java 2nd Edition, Item 49: Prefer primitives to boxed primitives:
In summary, use primitives in preference to boxed primitive whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the
==operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throwNullPointerException. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.
There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.
References
- JLS 4.2. Primitive Types and Values
- "The numeric types are the integral types and the floating-point types."
- JLS 5.1.8 Unboxing Conversion
- "A type is said to be convertible to a numeric type if it is a numeric type, or it is a reference type that may be converted to a numeric type by unboxing conversion."
- "Unboxing conversion converts [...] from type
Integerto typeint" - "If
risnull, unboxing conversion throws aNullPointerException"
- Java Language Guide/Autoboxing
- JLS 15.21.1 Numerical Equality Operators
==and!= - JLS 15.21.3 Reference Equality Operators
==and!= - JLS 5.6.2 Binary Numeric Promotion
Related questions
- When comparing two
Integersin Java does auto-unboxing occur? - Why are these
==but notequals()? - Java: What’s the difference between autoboxing and casting?
Related questions
- What is the difference between an int and an Integer in Java/C#?
- Is it guaranteed that new Integer(i) == i in Java? (YES!!! The box is unboxed, not other way around!)
- Why does
int num = Integer.getInteger("123")throwNullPointerException? (!!!) - Java noob: generics over objects only? (yes, unfortunately)
- Java
String.equalsversus==
Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if i is null.
it is possible to handle null pointer exception using Comparator.comparing static method. If you want to comparing loanAmount fields in your objects and you want that every not null value is greater than null you can use Comparator.nullFirst method in combination with Comparator.comparing like the below code:
Comparator.comparing(LoanAccount::getLoanAmount,
Comparator.nullsFirst(Comparator.naturalOrder()))
NaturalOrder is a method returning a comparator that compares Comparable objects in natural order.
You can also combine more comparators in a chain with method Comparator.thenComparing like the code below:
Comparator
.comparing(LoanAccount::getLoanAmount,
Comparator.nullsFirst(Comparator.naturalOrder()))
.thenComparing(LoanAccount::getCreationDate,
Comparator.nullsFirst(Comparator.naturalOrder()))
.compare(o1, o2);
Now you can rewrite your comparator with equal behaviour shortly:
public class LoanAccountAmountComparator
implements Comparator<LoanAccount> {
@Override
public int compare(LoanAccount o1, LoanAccount o2) {
if (o1 == null && o2 == null) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return Comparator
.comparing(LoanAccount::getLoanAmount,
nullsFirst(naturalOrder()))
.thenComparing(LoanAccount::getCreationDate,
nullsFirst(naturalOrder()))
.compare(o1, o2);
}
}
Note: the use of class Date is discouraged, it is better if you use instead the java.time package classes for time related code.
Here is another twist, roughly similar to dariosicily's proposal.
It differs in the following points:
- It create the aggregated comparator only once, then store it in a static field. Why? Because functions such as
Comparator.nullsFirst()andComparator.comparing()implies object allocation, which you definitely want to avoid if your comparator is called from tight loops (for example, a sort or tree insertion algorithm). - Null checks on the LoadAccount objects themselves have also been delegated to
Comparator.nullsFirst(). That means that absolutely noifstatement is required! - I moved that comparator to a public, static field of a utility class. I have learned from personal experience that comparators on domain model objects very often come in "families". In different places, you want different sorting strategies, for the same objects. Here, for demonstration, I also included one comparator for
loadAmount(that is, without fallback on tie), and another one forcreationDate. But you can see how this idea can be generalized. - In this sample, I have adopted an uncommon indentation strategy. I think this is justified in this case because it helps make it easier to see which fields are sorted by each comparator, and in which order. This is of great importance when you have comparators that involve a significant number of fields.
public class LoanAccountAmountComparators {
/**
* A comparator that sort LoanAccounts, by load's amount, in decreasing order.
*/
public static final Comparator<LoanAccount> BY_AMOUNT =
Comparator.nullsFirst(
Comparator.comparing(
LoanAccount::getLoanAmount, Comparator.nullsFirst(Comparator.reverseOrder())
);
);
/**
* A comparator that sort LoanAccounts, by creation date, in ascending order.
*/
public static final Comparator<LoanAccount> BY_DATE =
Comparator.nullsFirst(
Comparator.comparing(
LoanAccount::getCreationDate, Comparator.nullsFirst(Comparator.naturalOrder())
);
);
/**
* A comparator that sort LoanAccounts, by creation amount (in descending order),
* then by date (in ascending order).
*/
public static final Comparator<LoanAccount> BY_AMOUNT_AND_DATE =
Comparator.nullsFirst(
Comparator.comparing(
LoanAccount::getLoanAmount, Comparator.nullsFirst(Comparator.reverseOrder())
).thenComparing(
LoanAccount::getCreationDate, Comparator.nullsFirst(Comparator.naturalOrder())
);
);
}
It should be noted that, in this example, all fields involved are indeed some kind of objects. If, however, your comparator would involve fields containing primitive types, then you should use the corresponding Comparator.comparing<primitiveType> function (that is, never let some primitive be boxed to object only so it can be compared to Comparator.naturalOrder().
From javadoc for Comparable
Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
Yes, there is no problem allowing null for instance fields - just make sure its sorting order is defined. Most natural would be putting it either before or after all real strings, but you could do anything here, just do it consistently. (For example, you could sort null like "null".)
Here is an example implementation for a single member:
class Example implements Comparable<Example> {
@Nullable
private String member;
// TODO: getter, setter, constructor, ...
public int compareTo(Example that) {
if(this.member == null)
if(that.member == null)
return 0; //equal
else
return -1; // null is before other strings
else // this.member != null
if(that.member == null)
return 1; // all other strings are after null
else
return this.member.compareTo(that.member);
}
}
Please note that the specification of Comparable.compareTo() only has a constraint for o.compareTo(null) (which should behave just like - null.compareTo(o), i.e. throw a NullPointerException), but not about how null fields are handled (it doesn't mention fields at all, so a class could return whatever it wants, as long as the antisymmetry, reflexivity and transitivity is ensured).
No, == between Integer, Long etc will check for reference equality - i.e.
Integer x = ...;
Integer y = ...;
System.out.println(x == y);
this will check whether x and y refer to the same object rather than equal objects.
So
Integer x = new Integer(10);
Integer y = new Integer(10);
System.out.println(x == y);
is guaranteed to print false. Interning of "small" autoboxed values can lead to tricky results:
Integer x = 10;
Integer y = 10;
System.out.println(x == y);
This will print true, due to the rules of boxing (JLS section 5.1.7). It's still reference equality being used, but the references genuinely are equal.
If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.
Personally I'd use:
if (x.intValue() == y.intValue())
or
if (x.equals(y))
As you say, for any comparison between a wrapper type (Integer, Long etc) and a numeric type (int, long etc) the wrapper type value is unboxed and the test is applied to the primitive values involved.
This occurs as part of binary numeric promotion (JLS section 5.6.2). Look at each individual operator's documentation to see whether it's applied. For example, from the docs for == and != (JLS 15.21.1):
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
and for <, <=, > and >= (JLS 15.20.1)
The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs. Binary numeric promotion is performed on the operands (§5.6.2). If the promoted type of the operands is int or long, then signed integer comparison is performed; if this promoted type is float or double, then floating-point comparison is performed.
Note how none of this is considered as part of the situation where neither type is a numeric type.
Since Java 1.7 you can use Objects.equals:
java.util.Objects.equals(oneInteger, anotherInteger);
Returns true if the arguments are equal to each other and false otherwise. Consequently, if both arguments are null, true is returned and if exactly one argument is null, false is returned. Otherwise, equality is determined by using the equals method of the first argument.
Personally, I like Guava's Ordering for null-safe comparing. You can specify #nullsFirst() or #nullsLast() to avoid NullPointerExceptions.
Other important notes, mostly from the comments:
thisis nevernullin Java- Consider using Guava's
ComparisonChainif you're implementing a fine-grainedcompareTo() When implementing
Comparable, be sure to specify the type parameter so you get compile-time type safety and don't have to useinstanceofor casts:class Tok implements Comparable<Tok> { // snip public int compareTo(Tok other) { // snip } }
Returning 0 would imply that this and o are equal, which isn't true if o is null. Also, this will never be null.
It's application-dependent, of course. You may want to have an object that should be equal to null. What you return there is up to you, but if you're looking for a general null safe method, it isn't really ideal.
To be completely generic, I would check if o is null and, if so, throw some sort of Exception.