我想通过 String.CompareTo 比较器对静态字符串数组进行排序和二分搜索。
问题是排序和二分查找都需要传入 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);
}
}
基于 java.util.Comparator.comparing(...)的 Java 8 解决方案:
Comparator<String> c = Comparator.comparing(String::toString);
或
Comparator<String> c = Comparator.comparing((String x) -> x);
Arrays
类有sort()
和binarySearch()
的版本,它们不需要Comparator.
例如,您可以使用Arrays.sort()
的版本,它只需要一个对象数组。这些方法调用数组中对象的 compareTo()
方法。
好吧,这是几年后的事了,但在 java 8 中你可以使用 Comparator.naturalOrder():
http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#naturalOrder--
来自javadoc:
static <T extends Comparable<? super T>> Comparator<T> naturalOrder()
返回一个按自然顺序比较 Comparable 对象的比较器。 返回的比较器是可序列化的,并且在比较 null 时抛出 NullPointerException。
这是任何类型
Comparator
对象的通用 Comparable
,而不仅仅是 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 );
}
}
如何与
String
一起使用:
Comparator<String> stringComparator = DefaultComparator.getInstance();
再次强调,只要对象的类型是可比较的,就不需要
Arrays.binarySearch(Object[] a, Object key)
的比较器,但是使用 lambda 表达式,现在这变得更容易。
只需将比较器替换为方法参考:
String::compareTo
例如:
Arrays.binarySearch(someStringArray, "The String to find.", String::compareTo);
你也可以使用
Arrays.binarySearch(someStringArray, "The String to find.", (a,b) -> a.compareTo(b));
但即使在 lambda 之前,也总是存在匿名类:
Arrays.binarySearch(
someStringArray,
"The String to find.",
new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
此外,如果您想要不区分大小写的比较,在最新版本的 Java 中,
String
类包含一个名为 public static final
的 CASE_INSENSITIVE_ORDER
字段,其类型为 Comparator<String>
,正如我最近发现的那样。因此,您可以使用 String.CASE_INSENSITIVE_ORDER
来完成您的工作。
我们可以使用 String.CASE_INSENSITIVE_ORDER 比较器以不区分大小写的顺序比较字符串。
Arrays.binarySearch(someStringArray, "The String to find.",String.CASE_INSENSITIVE_ORDER);
我发现最干净的方法是使用 lambda 表达式。
像这样:
strings.sort((a, b) -> a.compareTo(b));
如果你想了解更多——
在 javascript 或其他函数式语言中,我们可以简单地传递一个函数作为参数,即
compareTo
本身就是一个 Comparator
。
在java中,函数不是一等公民。因此,您需要将其包装在一个子类
Comparator
的类中,并将该方法定义为该类的 only 方法。
当然,它看起来很奇怪而且冗长,b/c OOP 并不是为了做这样的事情而设计的。 Lambda 表达式在幕后正是执行此操作(子类化、定义方法),尽管表达式本身看起来与函数式语言中的相同。
关于Nambari的答案有一个错误。如果使用双等号 == 比较值,程序将永远不会到达比较方法,除非有人使用 new 关键字来创建 String 对象,这不是最佳实践。这可能是一个更好的解决方案:
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);
}
附注感谢您的评论;)
您可以使用
StringUtils.compare("a", "b")