Java 如何使用比较器比较空值?
我有一些比较器-,一个用于日期,一个用于小数,一个用于百分比,等等 起初,我的十进制比较器如下所示:Java 如何使用比较器比较空值?,java,refactoring,comparator,Java,Refactoring,Comparator,我有一些比较器-,一个用于日期,一个用于小数,一个用于百分比,等等 起初,我的十进制比较器如下所示: class NumericComparator implements Comparator<String> { @Override public int compare(String s1, String s2) { final Double i1 = Double.parseDouble(s1); final Double i2 = Double.pars
class NumericComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
final Double i1 = Double.parseDouble(s1);
final Double i2 = Double.parseDouble(s2);
return i1.compareTo(i2);
}
}
生活更美好。测试感觉更加可靠。然而,我的代码审阅者指出,“那么null
s呢?”
很好,现在我必须用NullPointerException
重复上述内容,或者在方法体前面加上:
if (s1 == null) {
if (s2 == null) {
return 0;
} else {
return -1;
}
} else if (s2 == null) {
return 1;
}
这种方法是巨大的。最糟糕的是,我需要用另外三个类重复这个模式,它们比较不同类型的字符串,并且在解析时可能引发另外三个异常
我不是Java专家。有比复制和粘贴更干净、更整洁的解决方案吗?只要有文档记录,我是否应该以正确性换取复杂性的缺乏
更新:一些人认为处理
null
值不是比较器的工作。由于排序结果显示给用户,我确实希望对空值进行一致的排序。您可以创建一个实用方法,在空值或解析异常的情况下处理解析并返回特定值。这个问题有很多主观答案。这是我自己的0.02美元
首先,您所描述的问题是缺乏一流函数的语言的典型症状,这将使您能够简洁地描述这些模式
其次,在我看来,如果两个字符串中的一个不能被视为双精度的表示,那么将两个字符串作为双精度进行比较应该是错误的。(对于null等也是如此)因此,应该允许异常传播!我认为这将是一个有争议的观点。如果您能够更改签名,我建议您编写该方法,以便它可以接受任何受支持的对象
public int compare(Object o1, Object o2) throws ClassNotFoundException {
String[] supportedClasses = {"String", "Double", "Integer"};
String j = "java.lang.";
for(String s : supportedClasses){
if(Class.forName(j+s).isInstance(o1) && Class.forName(j+s).isInstance(o1)){
// compare apples to apples
return ((Comparable)o1).compareTo((Comparable)o2);
}
}
throw new ClassNotFoundException("Not a supported Class");
}
您甚至可以递归地定义它,将字符串转换为Double,然后返回使用这些对象调用自身的结果。您应该首先创建一个从字符串返回Double的方法,嵌入null和解析失败案例(但您必须定义在这种情况下的操作:抛出异常?返回默认值??)
然后,比较器只需比较获得的双实例
换句话说,重构
但是我仍然想知道为什么你需要比较字符串,尽管你希望它们代表双精度。我的意思是,是什么阻止你在实际使用这个比较器的代码中操作双精度呢?你正在实现一个比较器字符串的方法,包括compareTo
抛出一个空点EXCEOption
如果将null交给它们,那么您也应该这样做。类似地,Comparator
如果参数的类型阻止它们进行比较,则抛出一个ClassCastException
。我建议您实现这些继承的行为
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1;
final Double i2;
if(s1 == null)
{
throw new NullPointerException("s1 is null"); // String behavior
}
try {
i1 = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException("s1 incorrect format"); // Comparator behavior
}
if(s2 == null)
{
throw new NullPointerException("s2 is null"); // String behavior
}
try {
i2 = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException("s2 incorrect format"); // Comparator behavior
}
return i1.compareTo(i2);
}
}
类NumericComparator实现Comparator{
公共整数比较(字符串s1、字符串s2){
最终双i1;
最终双i2;
如果(s1==null)
{
抛出新的NullPointerException(“s1为null”);//字符串行为
}
试一试{
i1=Double.parseDouble(s1)
}捕获(数字格式){
抛出新的ClassCastException(“s1格式不正确”);//比较器行为
}
if(s2==null)
{
抛出新的NullPointerException(“s2为null”);//字符串行为
}
试一试{
i2=Double.parseDouble(s1)
}捕获(数字格式){
抛出新的ClassCastException(“s2格式不正确”);//比较器行为
}
返回i1。比较(i2);
}
}
通过进行类型检查和转换,您几乎可以恢复原始的优雅
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1;
final Double i2;
i1 = parseStringAsDouble(s1, "s1");
i2 = parseStringAsDouble(s2, "s2");
return i1.compareTo(i2);
}
private double parseStringAsDouble(String s, String name) {
Double i;
if(s == null) {
throw new NullPointerException(name + " is null"); // String behavior
}
try {
i = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException(name + " incorrect format"); // Comparator behavior
}
return i;
}
}
类NumericComparator实现Comparator{
公共整数比较(字符串s1、字符串s2){
最终双i1;
最终双i2;
i1=parseStringAsDouble(s1,“s1”);
i2=parseStringAsDouble(s2,“s2”);
返回i1。比较(i2);
}
私有双parseStringAsDouble(字符串s,字符串名称){
双i;
如果(s==null){
抛出新的NullPointerException(name+“is null”);//字符串行为
}
试一试{
i=Double.parseDouble(s1)
}捕获(数字格式){
抛出新的ClassCastException(名称+“格式不正确”);//比较器行为
}
返回i;
}
}
如果您对异常消息不太在意,您可能会丢失“name”参数。我确信,通过应用一些小技巧,您可能会在这里或那里丢失额外的一行或多个单词
你说你需要用另外三个类来重复这个模式,它们比较不同类型的字符串,并且可能引发另外三个异常。在没有看到情况的情况下,很难提供详细信息,但是你可以在myparseStringAsDouble
的一个版本上使用到Nume的一个共同祖先中ricComparator
本身实现java的比较器
请后退一步。那些字符串
来自何处?这个比较器
将用于什么?您是否有一个字符串的集合
,希望对其进行排序
所以我改进了compare()
当然有
首先,Comparator接口没有指定null的情况。如果null检查if语句适用于您的用例,这很好,但是一般的解决方案是抛出一个npe
至于清洁剂…为什么是最终的?为什么所有的捕获/抛出?为什么使用compareTo作为原始包装
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) throws NullPointerException, NumberFormatException {
double test = Double.parseDouble(s1) - Double.parseDouble(s2);
int retVal = 0;
if (test < 0) retVal = -1;
else if (test > 0) retVal = 1;
return retVal;
}
}
类NumericComparator实现Comparator{
公共int比较(字符串s1、字符串s2)引发NullPointerException、NumberFormatException{
双重测试=double.parseDouble(s1)-double.parseDouble(s2);
int-retVal=0;
如果(测试<0)retVal=-1;
如果(测试>0)retVal=1,则为else;
返回返回;
}
}
看来你可能会被解雇
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) throws NullPointerException, NumberFormatException {
double test = Double.parseDouble(s1) - Double.parseDouble(s2);
int retVal = 0;
if (test < 0) retVal = -1;
else if (test > 0) retVal = 1;
return retVal;
}
}
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
Ordering.nullsFirst().onResultOf(
new Function<String, Double>() {
public Double apply(String s) {
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
return null;
}
})
private Double getDouble(String number) {
try {
return Double.parseDouble(number);
} catch(NumberFormatException e) {
return null;
}
}
if i1==null && i2!=null return -1
if i1==null && i2==null return 0
if i1!=null && i2==null return 1
if i1!=null && i2!=null return comparison
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1 = getDouble(s1);
final Double i2 = getDouble(s2);
return (i1 == null) ? (i2 == null) ? 0 : -1 : (i2 == null) ? 1 : i1.compareTo(i2);
}
private Double getDouble(String number) {
try {
return Double.parseDouble(number);
} catch(NumberFormatException e) {
return null;
}
}
}
public class ParsingComparator implements Comparator<String> {
private Parser parser;
public int compare(String s1, String s2) {
Object c1 = parser.parse(s1);
Object c2 = parser.parse(s2);
new CompareToBuilder().append(c1, c2).toComparison();
}
}
class NumericComparator implements Comparator<String> {
private SafeAdaptor<Double> doubleAdaptor = new SafeAdaptor<Double>(){
public Double parse(String s) {
return Double.parseDouble(s);
}
};
public int compare(String s1, String s2) {
final Double i1 =doubleAdaptor.getValue(s1, "s1");
final Double i2 = doubleAdaptor.getValue(s2, "s2");
return i1.compareTo(i2);
}
}
abstract class SafeAdaptor<T>{
public abstract T parse(String s);
public T getValue(String str, String name) {
T i;
if (str == null) {
throw new NullPointerException(name + " is null"); // String
}
try {
i = parse(str);
} catch (NumberFormatException e) {
throw new ClassCastException(name + " incorrect format"); // Comparator
}
return i;
}
}