You put your data into a
collection in random order or used a
Properties
object that doesn’t preserve the
order, and now you want it sorted.
If your data is in an array, you can sort it using the static
sort( )
method of the
Arrays
utility class. If it is in a collection, you can use the static
sort( )
method of the
Collections
class. Here is a set of
strings being sorted, first in an
Array
and then in a Vector
:
public class SortArray { public static void main(String[] unused) { String[] strings = { "painful", "mainly", "gaining", "raindrops" }; Arrays.sort(strings); for (int i=0; i<strings.length; i++) System.out.println(strings[i]); } } public class SortCollection { public static void main(String[] unused) { Vector v = new Vector( ); v.add("painful"); v.add("mainly"); v.add("gaining"); v.add("raindrops"); Collections.sort(v); for (int i=0; i<v.size( ); i++) System.out.println(v.elementAt(i)); } }
What if the default sort ordering isn’t what you want? Well,
there is a
Comparator
interface, and you can create an
object that implements it and pass that as the second argument to
sort. Fortunately, for the most common ordering next to the default,
you don’t have to; there is
a public constant
String.CASE_INSENSITIVE_ORDER
that can be passed
as this second argument. The String
class defines
it as “a Comparator
that orders
String
objects as by
compareToIgnoreCase
.” But if you need
something fancier, you need to write a Comparator
.
Suppose that, for some strange reason, you need to sort strings the
first character of each. One way to do this would be to
write this Comparator
:
public class SubstringComparator implements java.util.Comparator { public int compare(Object o1, Object o2) { String s1 = o1.toString( ).substring(1); String s2 = o2.toString( ).substring(1); return s1.compareTo(s2); // or, more concisely: // return o1.substring(1).equals(o2.substring(1)); } }
Using it is just a matter of passing it as the
Comparator
argument to the correct form of
sort( )
, as shown
here:
import java.util.*; public class SubstrCompDemo { public static void main(String[] unused) { String[] strings = { "painful", "mainly", "gaining", "raindrops" }; Arrays.sort(strings); dump(strings, "Using Default Sort"); Arrays.sort(strings, new SubstringComparator( )); dump(strings, "Using SubstringComparator"); } static void dump(String[] args, String title) { System.out.println(title); for (int i=0; i<args.length; i++) System.out.println(args[i]); } }
Here is the output of running it:
$ java SubstrCompDemo Using Default Sort gaining mainly painful raindrops Using SubstringComparator raindrops painful gaining mainly
And this is all as it should be.
On the other hand, you may be writing a class and want to build in
the comparison functionality,
so that you don’t
always have to remember to pass the Comparator
with it. In this case, you can directly implement the
java.lang.Comparable
interface. The
String
class, the wrapper classes
Byte
, Character
,
Double
, Float
,
Long
, Short
, and
Integer
, as well as BigInteger
and BigDecimal
from java.math
,
File
from java.io
,
java.util.Date
, and
java.text.CollationKey
all implement this
interface, so arrays or Collections
of these can
be sorted without providing a Comparator
. Classes
that implement Comparable
are said to have a
"natural” ordering. The
documentation strongly recommends that a class’s natural
ordering be consistent with its equals( )
method, and it is
consistent with equals( )
if and only if
e1.compareTo((Object)e2)==0
has the same boolean
value as e1.equals((Object)e2)
for every instance
e1
and e2
of the given class.
This means that if you implement Comparable
, you
should also implement equals( )
, and the logic of
equals( )
should be consistent with the logic of
the compareTo( )
method. Here, for example, is part of the
appointment class Appt
from a hypothetical
scheduling program:
public class Appt implements Comparable { // much code and variables omitted - see online version //----------------------------------------------------------------- // METHODS - COMPARISON //----------------------------------------------------------------- /** compareTo method, from Comparable interface. * Compare this Appointment against another, for purposes of sorting. * <P>Only date and time participate, not repetition! * Consistent with equals( ). * @return -1 if this<a2, +1 if this>a2, else 0. */ public int compareTo(Object o2) { Appt a2 = (Appt) o2; if (year < a2.year) return -1; if (year > a2.year) return +1; if (month < a2.month) return -1; if (month > a2.month) return +1; if (day < a2.day) return -1; if (day > a2.day) return +1; if (hour < a2.hour) return -1; if (hour > a2.hour) return +1; if (minute < a2.minute) return -1; if (minute > a2.minute) return +1; return target.compareTo(a2.target); } /** Compare this appointment against another, for equality. * Consistent with compareTo( ). For this reason, only * date & time participate, not repetition. * @returns true if the objects are equal, false if not. */ public boolean equals(Object o2) { Appt a2 = (Appt) o2; if (year != a2.year || month != a2.month || day != a2.day || hour != a2.hour || minute != a2.minute) return false; return target.equals(a2.target); }
If you’re still confused between
Comparable
and Comparator
,
you’re probably not alone. This table summarizes the two
“comparison” interfaces:
3.16.217.187