Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Toward null-safe cookie-cutter Comparators

1 view
Skip to first unread message

Roedy Green

unread,
Nov 13, 2011, 11:51:00 AM11/13/11
to
I have been hand-writing some Comparators. The catch is some of the
fields in the two objects I am comparing might be null.

This greatly messes up the code. Dealing with the four cases.

e.g. crudely coded like this:
----------------------------
if ( a.species == null && b.species == null ) return 0;
else if ( a.species == null && b.species != null ) return -1;
else if( a.species != null && b.species == null ) return 1;
else if( a.species != null && b.species != null ) return
a.species.compareToIgnoringCase( b.species);
else { throw new Exception ("Aristotle was wrong"); }
----------------------------
If I generated code to do this for you in the ComparatorCutter,
http://mindprod.com/applet/comparatorcutter.html
how would you prefer it be done?
----------------------------
if ( a.species == null )
{
return ( b.species == null ) ? 0 : -1;
}
else
{
return a.species.compareToIgnoringCase( b.species );
}
----------------------------
final String aSpecies = a.species == null ? "" : a.species;
final String bSpecies = b.species == null ? "" : b.species;
return aSpecies.compareTo( bSpecies );
----------------------------
return ( a.species == b.species )
|| (a == null) -1: aSpecies.compareTo( bSpecies );

// Quickly catches null/null and identity/interned match too, common
// leaves it up to compareTo to deal with null. There is no official
// guarantee that a comparator will support null parms.
// However this will not work since String.compareTo does not support
// null parms.!!!
---------------------------
int choose 0;
if ( a.species != null ) choose += 2;
if ( b.species != null) choose += 1;
switch (choose )
{
case 0: return 0;
case 1: return -1;
case 2: return 1;
case 3 : return a.species.compareTo( b.species );
default : err.println( "huh?");
}
----------------------------
return nullSafeStringCompare ( a.species, b.species );
// implementation to come, based on one of the other ways of coding it
inline.
----------------------------
something using the ^ xor operator.
----------------------------
In the olden days you just laid out a decision table and what you
wanted to happen for each combination of options and the PET
precompiler generated the optimal code for it.

e.g
null? null? what to do
a.species b.species
Y Y return 0;
Y N return -1;
N Y return 1;
N N return
a.species.compareToIgnoringCase(
----------------------------

something better?

All this code was just off the top of my head. It is just intended to
suggest the approach. It is not intended to be used precisely as is.

--
Roedy Green Canadian Mind Products
http://mindprod.com
I can't come to bed just yet. Somebody is wrong on the Internet.

Roedy Green

unread,
Nov 13, 2011, 1:22:21 PM11/13/11
to
Here is what I am using now:

/**
* Like String.compareIgnoreCase except it is not phased
* by null parameters.
* null sorts before everything else.
* @param a first string to compare, possibly null.
* @param b second string to compare, possibly null.
* @return -1 if a is less than b, 0 if a == b, and +1 if a is
greater than b
* comparing case-insensitively, e.g. interleaving upper and
lower case letters.
*/
public static int nullSafeStringCompareIgnoreCase( String a,
String b )
{
// catches 100% of equal if interned, otherwise just some,
//noinspection StringEquality
if ( a == b )
{
return 0;
}
else if ( a == null )
{
// b cannot be null;
return -1;
}
else if ( b == null )
{
// a cannot be null
return 1;
}
else
{
// a and b cannot be null
return a.compareToIgnoreCase( b );
0 new messages