java - 如何使用比较器比较空值?

标签 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.parseDouble(s2);
    return i1.compareTo(i2);
  }

}

生活很简单。当然,这不能处理字符串不可解析的情况。所以我改进了compare():

class NumericComparator implements Comparator<String> {

  @Override
  public int compare(String s1, String s2) {
    final Double i1;
    final Double i2;

    try {
      i1 = Double.parseDouble(s1);
    } catch (NumberFormatException e) {
      try {
        i2 = Double.parseDouble(s2);
      } catch (NumberFormatException e2) {
        return 0;
      }
      return -1;
    }
    try {
      i2 = Double.parseDouble(s2);
    } catch (NumberFormatException e) {
      return 1;
    }

    return i1.compareTo(i2);
  }
}

生活更美好。测试感觉更可靠。但是,我的代码审阅者指出,“null 怎么样?”

太好了,所以现在我必须用 NullPointerException 重复上面的操作,或者在方法体前面加上:

if (s1 == null) {
  if (s2 == null) {
    return 0;
  } else {
    return -1;
  }
} else if (s2 == null) {
  return 1;
}

这个方法很庞大。最糟糕的是,我需要用 三个其他类 重复此模式,这些类比较不同类型的字符串并可能在解析时引发 三个其他异常

我不是 Java 专家。有比复制和粘贴更干净、更简洁的解决方案吗?gasp?只要记录在案,我是否应该用正确性来换取不复杂性?


更新:有人建议处理null 值不是Comparator 的工作。由于排序结果显示给用户,我确实希望空值一致地排序。

最佳答案

您正在实现 Comparator<String> . String的方法,包括compareTo扔一个NullPointerException如果将空值交给他们,那么您也应该这样做。同样,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);
  }
}

extracting a method 几乎可以重拾最初的优雅进行类型检查和转换。

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;
  }
}

如果您对异常消息不特别在意,则可以省略“name”参数。我敢肯定,您可以通过应用小技巧在这里少写一行或多写一个词。

你说你需要 repeat this pattern with three other classes which compare different types of strings and could raise three other exceptions .在没有看到情况的情况下很难在那里提供细节,但你可以使用 "Pull Up Method"在我的一个版本上 parseStringAsDouble成为NumericComparator的共同祖先它本身实现了 java 的 Comparator .

关于java - 如何使用比较器比较空值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1682784/

相关文章:

java - 无法在我的 Spring 引导项目中使用 Maven 依赖项

java - 使用 Linux more 命令时 Runtime.getRuntime().exec() 挂起

java - 如何对同一类型的 Checkstyle 问题应用多个快速修复?

java - Java中什么时候用Comparator,什么时候用Comparable?

java - Struts.xml Action 配置

Java - 找不到构造函数?

java-8 - 从 Joda 时间库迁移到 Java 时间(Java 8)

java - 如何重构 validator

Java 8 Lambda 表达式

java比较器,按单词数比较字符串