1. 概述

Java 5 引入了枚举(Enums),提供了一种安全且整洁的方式来管理常量。在这篇快速教程中,我们将探讨如何比较一个String对象与枚举对象。

2. 问题介绍

首先,让我们看一个枚举的例子:

enum Weekday {
    Mon("Monday"),
    Tue("Tuesday"),
    Wed("Wednesday"),
    Thu("Thursday"),
    Fri("Friday"),
    Sat("Saturday");
                                 
    private String fullName;
                                 
    Weekday(String fullName) {
        this.fullName = fullName;
    }
                                 
    public String getFullName() {
        return fullName;
    }
}

如代码所示,Weekday枚举包含六个由每个工作日缩写命名的常量,并且它有一个名为fullName的属性,用于存储每个工作日的完整名称。

现在假设我们有一个字符串s。那么,将s与枚举实例进行比较可能有以下两种情况:

  • s与枚举实例的名称进行比较
  • s与枚举实例的一个String属性进行比较

本教程将涵盖这两种场景,并进行不区分大小写的比较。为了简化,我们将使用单元测试断言来验证比较结果。

接下来,我们创建两个String作为输入:

final String SAT = "sAt";
final String SATURDAY = "sAtuRdAy";

我们将使用SAT字符串进行枚举名称的比较,使用SATURDAY变量进行枚举属性的比较。为了完整,我们还需要为负测试创建另外两个String

final String TYPO_FRI = "ffri";
final String TYPO_FRIDAY = "ffriday";

理解如何比较String和枚举实例后,我们还将讨论这些比较的常见用例。现在,让我们实际操作一下。

3. 比较给定的String与枚举实例的名称或属性

首先,我们来看看如何将给定的String与枚举实例的名称进行比较。

**所有枚举类都继承自抽象类java.lang.Enum**。这个抽象类定义了一个name()方法,用于返回枚举实例的名称:

public abstract class Enum<E extends Enum<E>> implements Constable, Comparable<E>, Serializable {
    private final String name;
    ...

    public final String name() {
        return this.name;
    }
...

因此,我们可以使用name()方法获取枚举常量的名称,并与给定的String进行比较:

assertTrue(SAT.equalsIgnoreCase(Sat.name()));
assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.name()));

如上面的测试所示,我们使用了equalsIgnoreCase()方法进行不区分大小写的比较。

我们提到过,根据需求,我们可能想要将String与枚举常量的属性(如WeekdayfullName属性)进行比较。这并不困难,因为Weekday枚举有一个获取属性值的方法:

assertTrue(SATURDAY.equalsIgnoreCase(Sat.getFullName()));
assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.getFullName()));

所以,正如我们所见,无论哪种场景,将String与枚举进行比较都非常直接。

但在实际应用中,我们会在什么情况下需要这种比较呢?让我们通过例子来讨论。

4. 通过给定的String查找枚举实例

一个常见的需要比较的情况是根据给定的String确定枚举实例。例如,我们想通过字符串“SAT”找到Weekday.Sat常量。

接下来,我们在Weekday枚举中添加两个“查找”方法:

enum Weekday {
    Mon("Monday"),
    ...

    static Optional<Weekday> byNameIgnoreCase(String givenName) {
        return Arrays.stream(values()).filter(it -> it.name().equalsIgnoreCase(givenName)).findAny();
    }

    static Optional<Weekday> byFullNameIgnoreCase(String givenFullName) {
        return Arrays.stream(values()).filter(it -> it.fullName.equalsIgnoreCase(givenFullName)).findAny();
    }
   ...
}

这两个方法的实现非常相似。一个用于按名称查找,另一个用于按fullName属性查找。

我们在实现中使用了流(Stream API)。首先,values()是一个静态方法,它在任何枚举类型中可用,并返回对应枚举类型的所有枚举常量数组。因此,Weekday.values()给我们提供了所有的Weekday常量。

然后,我们将常量数组转换为Stream对象。接下来,我们将不区分大小写的比较逻辑传递给filter()方法,作为lambda表达式

由于我们不确定filter()方法是否能找到匹配的枚举实例,我们返回findAny()方法的结果,这是一个Optional<Weekday>对象。调用者可以根据这个Optional结果决定下一步的操作。现在,让我们看看在测试方法中它是如何工作的:

Optional<Weekday> optResult = Weekday.byNameIgnoreCase(SAT);
assertTrue(optResult.isPresent());
assertEquals(Sat, optResult.get());
                                                                  
Optional<Weekday> optResult2 = Weekday.byNameIgnoreCase(TYPO_FRI);
assertFalse(optResult2.isPresent());

如上述测试所示,只有当byNameIgnoreCase()方法找到一个常量时,Optional结果的isPresent()才会返回true

这与“通过属性查找枚举常量”的场景非常相似。为了完整性,我们为byFullNameIgnoreCase()方法创建一个测试:

Optional<Weekday> optResult = Weekday.byFullNameIgnoreCase(SATURDAY);
assertTrue(optResult.isPresent());
assertEquals(Sat, optResult.get());
                                                                         
Optional<Weekday> optResult2 = Weekday.byFullNameIgnoreCase(TYPO_FRIDAY);
assertFalse(optResult2.isPresent());

5. 总结

在这篇文章中,我们学习了如何比较String与枚举常量。此外,我们通过示例讨论了比较的常见用例。

如往常一样,这里展示的所有代码片段都可以在GitHub上找到。