检查 Java 中三个或更多字符串的相等性

Checking equality of three or more Strings in Java

我知道这是一个非常基本的问题,但我一直在努力寻找使我的代码尽可能简洁明了的方法。有没有办法在单个 if() 语句中比较三个或更多字符串的相等性?我目前正在使用 && 运算符来逐步比较每个字符串。然而,正如您所想象的,在长变量名和被调用的方法之间,这些 if() 语句很快就会变得非常混乱。此外,我计划拥有未知数量的这些字符串,并希望避免复杂的 for 循环,其中嵌套了混乱的 if()。这是我的代码目前的样子:

String a = new String("a");
String b = new String("b");
String c = new String("c");
if(a.equals(b) && b.equals(c)) {
    doSomething();
}

有没有一种方法或某种集合可以让我更像这样比较这些值:

if(a.equals(b).equals(c)) {
    doSomething();
}

没有像这样链接 equals() 命令的简单方法。为了能够以这种方式链接它们,equals() 必须 return 对字符串本身的引用。然而,它不能再 return 表示比较结果的布尔值。

此外,我认为 不是特别有问题 像第一个示例那样分别比较三个字符串。确保您的代码格式正确,并且即使对于更长的变量名,它也将易于理解:

if(myValueAWithALongName.equals(myValueBWithALongName) &&
   myValueBWithALongName.equals(myValueCWithALongName) &&
   myValueCWithALongName.equals(myValueDWithALongName) &&
   ... ) {

或者,您可以使用此线程中提出的其他解决方案之一,将您的值包装到一个集合中并编写一个辅助方法。但是请注意,这可能会对内存使用、性能和可读性产生负面影响。


附带说明一下,您永远不应该使用构造函数 new String() 创建字符串。只需将字符串文字直接分配给您的变量:

String a = "a";

这样的事情怎么样:

boolean allEqual(List<String> elements) {
    if(elements.isEmpty() || elements.size() == 1) {
        return true;
    }
    String current = elements.get(0);
    if(current == null) {
        return false;
    }
    for(int i = 1; i < elements.size(); i++) {
        if(!current.equals(elements.get(i))) {
            return false;
        }
        current = elements.get(i);
    }
    return true;
}

不是很漂亮,但你只需要写一次,它适用于任意数量的字符串。

如果您有多个相同类型的对象,最好将它们组织在数组或列表等数据结构中。所以假设你有 ListString 个对象:

List<String> strings = Arrays.asList("a", "b", "a", ...);

您想知道列表中的所有字符串是否彼此相等。这可以通过多种方法完成。可能最短的是:

if(new HashSet<>(strings).size() == 1) {
    // all strings are equal
}

@niceguy 提出了更长但更优化的解决方案。如果你使用的是Java-8,你也可以这样做:

if(strings.stream().distinct().count() == 1) {
    // all strings are equal
}

另一种方法是使用 String 作为 Comparable 的实现。

public <T extends Comparable<T>> boolean equality(T... objects) {
    Arrays.sort(objects);
    return objects[0].compareTo(objects[objects.length - 1]) == 0;
}

优点: 此解决方案适用于所有 Comparable 个对象。

缺点:如果所有值都等于它将是 N(太棒了!)比较,否则 N logN 最大值。这里也将分配内存用于 sort 方法的临时存储,从非常小到 N/2

根据要比较的 String 个对象的数量,有不同的方法可以解决此问题。

如果您只有少数 String 个对象需要比较,并且您几乎需要在应用程序的一两个地方进行这种比较,您可以将代码包装在一个方法中class 需要这样的比较,以便代码变得更具可读性:

 public boolean isConditionSatisfied(String a,String b,String c) {
    return Objects.equals(a,b) && Objects.equals(b,c);
 }

然后简化客户端代码并使其更具可读性:

if(isConditionSatisfied(a,b,c)) { //doSomething }

请注意,Objects.equals 是自 JDK 1.7 以来可用的内置方法。与其他答案相比,使用 Object.equals 可以保护您免受 NullPointerExcsption 的影响,我认为这是绝对必要的。

如果您发现自己经常需要这种比较(而且不仅针对 String 个对象),为什么要寻找仅用于比较 String 个对象的解决方案?为什么不找到一个适用于任何种类或数量的对象的通用解决方案呢?

public class ObjectUtils {

    public static boolean multipleEquals(Object... objectsToCompare) {

        if (null == objectsToCompare) {
            return false;
        } else if (objectsToCompare.length == 0) {
            return false;
        } else if (objectsToCompare.length == 1)      {
            return true;
        }

        boolean allEqual = true;
        for (int curr = 1; curr < objectsToCompare.length; ++curr) {
            if(!Objects.equals(objectsToCompare[0],objectsToCompare[curr])) {
                allEqual = false;
                break;
            }
        }

        return allEqual;
    }
}

好的,所以你想比较 4 个 String 对象,为什么不呢:

if(ObjectUtils.multipleEquals("1","1","1","1") { }

但现在你想比较 5 个 Integer 个对象,没问题:

if(ObjectUtils.multipleEquals(1,2,3,4,5) { }

您甚至可以混合搭配对象:

if(ObjectUtils.multipleEquals("1",2,"3",4) { }

Additionally I am planning to have an unknown number of these Strings, and would like to avoid complex for loops with cluttered if()s nested inside of them.

我认为 for 循环不会那么复杂。

你当然可以通过尝试

来检查是否相等
a.equals(b)
b.equals(c)
etc.

但是将所有内容与 a 进行比较会得到相同的结果。如果一切都等于a,那么一切都彼此相等。

a.equals(b)
a.equals(c)
etc.

这使得 for 循环更简单。如果您不介意将 a 与自身进行比较的开销,您可以简单地检查整个数组或集合(或其他)是否与 for equality.

if 看起来也不杂乱。 return 一旦一对字符串不相等,就会从函数中退出。

这可能是一个不寻常的想法,但在这种情况下,一点元编程可能会派上用场。

public static void nEquals(int nOverloads, PrintStream out) {
    if (nOverloads < 2)
        throw new IllegalArgumentException();

    for (int i = 2; i <= nOverloads; ++i) {
        out.println("public static boolean equals(");
        out.print("        Object obj0");

        for (int j = 1; j < i; ++j) {
            out.print(", Object obj" + j);
        }

        out.println(") {");
        out.print("    return obj0.equals(obj1)");

        for (int j = 2; j < i; ++j) {
            out.print(" && obj0.equals(obj" + j + ")");
        }

        out.println(";");
        out.println("}");
    }
}

nEquals(4, System.out); 打印以下内容:

public static boolean equals(
        Object obj0, Object obj1) {
    return obj0.equals(obj1);
}
public static boolean equals(
        Object obj0, Object obj1, Object obj2) {
    return obj0.equals(obj1) && obj0.equals(obj2);
}
public static boolean equals(
        Object obj0, Object obj1, Object obj2, Object obj3) {
    return obj0.equals(obj1) && obj0.equals(obj2) && obj0.equals(obj3);
}

您可以根据需要生成任意数量的重载,无需可变参数。只需复制并粘贴到实用程序 class 即可。

if (Util.equals(a, b, c)) {
    doSomething();
}

对于如此简单的代码生成,错误余地很小。唯一的缺点是可维护性,因为如果有人确实需要修改它(例如更改 null 的处理,这在我和你的示例中都被忽略),他们需要修改生成器和 运行 它再次.