I would like to sort and binary search a static array of strings via the String.CompareTo comparator.
The problem is that both sorting, and binary searching requires that a Comparator object be passed in -- So how do I pass in the built in string comparator?
012 Answers
You may write your own comparator
public class ExampleComparator implements Comparator<String> { public int compare(String obj1, String obj2) { if (obj1 == obj2) { return 0; } if (obj1 == null) { return -1; } if (obj2 == null) { return 1; } return obj1.compareTo(obj2); } } 5Solution for Java 8 based on java.util.Comparator.comparing(...):
Comparator<String> c = Comparator.comparing(String::toString); or
Comparator<String> c = Comparator.comparing((String x) -> x); 2The Arrays class has versions of sort() and binarySearch() which don't require a Comparator. For example, you can use the version of Arrays.sort() which just takes an array of objects. These methods call the compareTo() method of the objects in the array.
Ok this is a few years later but with java 8 you can use Comparator.naturalOrder():
From javadoc:
static <T extends Comparable<? super T>> Comparator<T> naturalOrder() Returns a comparator that compares Comparable objects in natural order. The returned comparator is serializable and throws NullPointerException when comparing null.
1If you do find yourslef needing a Comparator, and you already use Guava, you can use Ordering.natural().
This is a generic Comparator for any kind of Comparable object, not just String:
package util; import java.util.Comparator; /** * The Default Comparator for classes implementing Comparable. * * @param <E> the type of the comparable objects. * * @author Michael Belivanakis (michael.gr) */ public final class DefaultComparator<E extends Comparable<E>> implements Comparator<E> { @SuppressWarnings( "rawtypes" ) private static final DefaultComparator<?> INSTANCE = new DefaultComparator(); /** * Get an instance of DefaultComparator for any type of Comparable. * * @param <T> the type of Comparable of interest. * * @return an instance of DefaultComparator for comparing instances of the requested type. */ public static <T extends Comparable<T>> Comparator<T> getInstance() { @SuppressWarnings("unchecked") Comparator<T> result = (Comparator<T>)INSTANCE; return result; } private DefaultComparator() { } @Override public int compare( E o1, E o2 ) { if( o1 == o2 ) return 0; if( o1 == null ) return 1; if( o2 == null ) return -1; return o1.compareTo( o2 ); } } How to use with String:
Comparator<String> stringComparator = DefaultComparator.getInstance(); 2Again, don't need the comparator for Arrays.binarySearch(Object[] a, Object key) so long as the types of objects are comparable, but with lambda expressions this is now way easier.
Simply replace the comparator with the method reference: String::compareTo
E.g.:
Arrays.binarySearch(someStringArray, "The String to find.", String::compareTo); You could also use
Arrays.binarySearch(someStringArray, "The String to find.", (a,b) -> a.compareTo(b)); but even before lambdas, there were always anonymous classes:
Arrays.binarySearch( someStringArray, "The String to find.", new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); Also, if you want case-insensitive comparison, in recent versions of Java the String class contains a public static final field called CASE_INSENSITIVE_ORDER which is of type Comparator<String>, as I just recently found out. So, you can get your job done using String.CASE_INSENSITIVE_ORDER.
We can use the String.CASE_INSENSITIVE_ORDER comparator to compare the strings in case insensitive order.
Arrays.binarySearch(someStringArray, "The String to find.",String.CASE_INSENSITIVE_ORDER); To generalize the good answer of Mike Nakis with String.CASE_INSENSITIVE_ORDER, you can also use :
Collator.getInstance(); See Collator
Regarding Nambari's answer there was a mistake. If you compare values using double equal sign == program will never reach compare method, unless someone will use new keyword to create String object which is not the best practice. This might be a bit better solution:
public int compare(String o1, String o2) { if (o1 == null && o2 == null){return 0;} if (o1 == null) { return -1;} if (o2 == null) { return 1;} return o1.compareTo(o2); } P.S. Thanks for comments ;)
2You can use the StringUtils.compare("a", "b")