重构这个简单方法的最有效方法是什么?

时间:2010-08-11 17:49:48

标签: java refactoring

我实施了一个非常简单的方法:

private String getProfileName(String path) {
    String testPath = null;
    for (int i = 0; i < path.length(); i++) {
       testPath = path.substring(0, i);
          if ( testPath.endsWith("1") || testPath.endsWith("2") || testPath.endsWith("3") || testPath.endsWith("4") || testPath.endsWith("5") || testPath.endsWith("6") || testPath.endsWith("7") || testPath.endsWith("8") || testPath.endsWith("9") ) {
            break;
          }
    }
    return testPath.substring(0, (testPath.length() - 1));
}

我不喜欢整个方法,因为我觉得它比必要的更复杂,特别是if条件。

所以我想到了一种重构这种方法的方法。首先我想用Regex替换if条件,但对于这个简单的情况,是不是正则表达式太多了?

其他任何想法如何重新审视?

10 个答案:

答案 0 :(得分:12)

将此模式与匹配器一起使用:

"^[^1-9]*"

示例代码:

private String getProfileName(String path) {
    Pattern pattern = Pattern.compile("^[^1-9]*");
    Matcher matcher = pattern.matcher(path);
    matcher.find();
    return matcher.group();
}

我认为这比你的代码更容易理解。我花了几分钟来计算你的逻辑,我必须运行它才能确定。我认为使用正则表达式很清楚代码在做什么。如果您希望可以只编译一次正则表达式,并通过将其移动到类的静态成员来重用它。

正则表达式对Stack Overflow有很大的耻辱(主要来自试图使用它们来解析HTML,电子邮件地址,URL以及各种其他令人讨厌的正则表达式的不当使用的人)。但是对于这种任务,正则表达式就好了。

您可能还想考虑为什么要省略0,如果这是个好主意。

答案 1 :(得分:7)

矿:

private String getProfileName(String path) {

    return path.split("[1-9]")[0];
}

希望这会对你有所帮助。

解释。正如Mark Byers所说,数字上的Split(第一个版本,第二个版本忽略0),并返回结果数组的第一个元素。但我认为如果第一个参数是一个数字(用jdk1.6.0_20测试),它不会失败。如果路径中的所有字符都是数字(例如“2223”),则会失败。您可以使用此版本来避免错误:

private String getProfileName(String path) {

    String[] result = path.split("[1-9]");
    return result.length > 0 ? result[0] : "";
}

正如您将在String's split method javadocs处看到的,它需要一个参数(正则表达式),您可以使用其中一个:

return path.split("[1-9]")[0]; //if you want to avoid 0
return path.split("\\d")[0]; //if you don't

恕我直言:如果您正在寻求提高代码可读性,使用split方法比其他方法更好,

答案 2 :(得分:6)

当然,你可以使用强力进行重构......但为什么不使用Apache Commons?

private String getProfileName(String path) {
    int index = StringUtils.indexOfAny(path, "123456789");
    if(index != -1) {
        return path.substring(0, index);
    }
    return path;
}

答案 3 :(得分:5)

除了正则表达式:

private static String getProfileName(String path) {
    final int len = path.length();
    for (int i=0; i<len; ++i) {
       char c = path.charAt(i);
       if ('1' <= c && c <= '9') {
           return i==0 ? "" : path.substring(0, i-1); // Probably don't want that -1 !!
       }
    }
    return len==0 ? "" : path.substring(0, len-1);
}

或者,对于Single Entry,Single Exit粉丝:

private static String getProfileName(String path) {
    final int len = path.length();
    int i=0;
    while (i != len && !isProfileTerminator(path.charAt(i))) {
    //Or (!(i == len || isProfileTerminator(path.charAt(i)))) {
       ++i;
    }
    return i==0 ? "" : path.substring(0, i-1);
}
private static boolean isProfileTerminator(char c) {
    return '1' <= c && c <= '9');
}

原始代码中存在问题,字符串为空或以1-9开头。

答案 4 :(得分:4)

  private String getProfileName(String path)
  {
    int i;
    for (i = 0; i < path.length() && !Character.isDigit(path.charAt(i)); i++);
    return path.substring(0, i);
  }

答案 5 :(得分:3)

我会说与正则表达式一起去。我想不出更简单的重构方法。我可能会想到更多复杂的方式,但我认为你不会想要那样。

答案 6 :(得分:2)

这是一个单行的正则表达式解决方案,非常简单:

private String getProfileName(String path) {
    return path.replaceFirst("(?s)\\d.*", "");
}

该模式在Pattern.DOTALL模式下为\d.*,为嵌入式标记(?s)。这将匹配一个数字,以及它之后的所有内容。我们想删除这部分,所以我们用空字符串替换。

请注意,\d也包含0,因此如果真的是规范,请替换为[1-9]

参考

答案 7 :(得分:1)

您可以创建一个这样的方法放入if

private static boolean endsWith1to9(String a) {
        for(int i = 1; i <= 9; i++) {
            if(a.endsWith(String.valueOf(i))) {
                return true;
            }
        }
        return false;
    }

答案 8 :(得分:1)

我觉得这样的事情会起作用。如果我错了,有人会纠正我。

private String getProfileName(String path) {
    int i = 0;
    for(i = 0; i < path.length; ++i)
    {
        if(path.charAt(i) > '0' && path.charAt(i) <= '9') break;
    }
    return path.substring(0, i-1);
}

答案 9 :(得分:1)

我的尝试:

/**
 * Numeric Register Optimized Search with Null Pointer Handling.
 * -> No use of Regex (per requirement). :)
 * -> No use of Character.isDigit() (NOTE: includes characters other than [0-9].)
 * -> Catch and Avoid NullPointerExceptions (Oops... review other methods above.)
 * -> Reduce for(...; test ; ...) to while(test) by variable declaration and ++off use.
 * -> Include ANDed test to avoid break call.
 * -> Cache "path.length" in local variable (e.g. CPU register)
 * -> Cache "path.charAt(off)" in local variable (e.g. CPU register)
 * -> Replace String.endsWith(...) Method with char < char Register Method.
 * -> Reuse path argument to avoid another internal object reference.
 * -> Avoid call to substring if [1-9] not found in path.
 * -> Single Entry/Single Exit Happy. :)
 * @return path null if passed null, otherwise valid value.
 */
private String getProfileName(String path) {
    if (path != null) {
        int off = -1, len = path.length;
        final char one = '1', nine = '9';
        char c;
        while (++off < len && (c = path.charAt(off)) < one && c > nine);
        if (off < len) {
            path = path.substring(0, off);
        }
    }
    return (path);
}
干杯, loeJava