【问题标题】:Check enum for multiple values检查枚举的多个值
【发布时间】:2015-01-26 04:21:46
【问题描述】:

我有一个枚举 FileType

public static enum FileType {
  CSV, XML, XLS, TXT, FIXED_LENGTH
}

FileType fileType = FileType.CSV;

是否有比以下方法更好(更简洁)的方法来检查 fileType 的多个值(例如 "myString".matches("a|b|c");)?

if(fileType == FileType.CSV || fileType == FileType.TXT || fileType == FileType.FIXED_LENGTH) {}

【问题讨论】:

  • 一个EnumSet?还是 FileType 枚举上的布尔字段?
  • EnumSet 是你想在这种情况下使用的

标签: java enums conditional-statements


【解决方案1】:

选项 1:向您的枚举添加一个布尔字段。

public static enum FileType {
    CSV(true), XML(false), XLS(false), TXT(true), FIXED_LENGTH(true);

    private final boolean interesting;

    FileType(boolean interesting) {
        this.interesting = interesting;
    }
    public boolean isInteresting() {
        return this.interesting;
    }
}

...

if (fileType!=null && fileType.isInteresting()) {
    ...
}

选项 2:使用EnumSet。 EnumSets 在后台使用位域,因此它们非常快且内存低。

Set<FileType> interestingFileTypes = EnumSet.of(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH);
...
if (interestingFileTypes.contains(fileType)) {
   ...
}

选项 3:按照 kocko 的建议使用 switch

【讨论】:

  • + 1 用于提及 EnumSet。请注意,EnumSet 只是 Set 的另一种实现,因此您可以编写:Set&lt;FileType&gt; interestingFileTypes = EnumSet.of(...);
【解决方案2】:

为什么不使用switch:

switch(fileType) {
   case CSV:
   case TXT:
   case FIXED_LENGTH:
       doSomething();
       break;
}

这与您的 if 语句检查相同,但它更具可读性,恕我直言。

但这段代码的问题不在于switch 或if/else 语句。问题是它破坏了Open-closed principle。

为了解决这个问题,我将完全删除enum 并创建一个界面:

interface FileType {
   boolean isInteresting();
}

然后,对于我们曾经拥有的每个枚举常量,我将创建一个单独的接口实现:

public class Txt implements FileType {
  @Override
  public boolean isInteresting() {
    return false;
  } 
}

switch 语句有何变化?我们曾经传递一个fileType 参数,我们检查了它的值。现在,我们将传递一个FileType 的实例。

public void method(FileType fileType) {
  if (fileType.isInteresting()) {
    doSomething();
  }
}

这样做的好处是当你引入一个新的FileType(你将作为一个新的枚举常量引入)时,你不必修改switch/if/else 语句来处理这种情况这种新的文件类型是否有趣。代码在这里直接工作,无需修改,这就是开闭原则的精髓:“对扩展开放,对修改关闭”。

【讨论】:

  • 更糟糕的是,它不是使用一长行,而是使用大量行,并使您的代码看起来更长。
  • @Hasen,实际上更糟糕的是,switch 语句(以及 if/else 方法)正在破坏 OOP 中的开闭原则。所以在这种情况下,我实际上会丢弃枚举和 if/else/switch 语句,而是使用带有一些实现的接口FileType。但请注意,我在 7 年前写过这个答案。 :) :)
  • @Hasen,我更新了我的答案,现在它实际上更好。长话短说:避免使用枚举和 switch 语句。这些带来的问题比你想象的要多。 :)
【解决方案3】:

我最终写了一个方法:

public static enum FileType {
  CSV, XML, XLS, TXT, FIXED_LENGTH;

  // Java < 8
  public boolean in(FileType... fileTypes) {
    for(FileType fileType : fileTypes) {
      if(this == fileType) {
        return true;
      }
    }

    return false;
  }

  // Java 8
  public boolean in(FileType... fileTypes) {
    return Arrays.stream(fileTypes).anyMatch(fileType -> fileType == this);
  }
}

然后:

if(fileType.in(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH)) {}

又好又干净!

【讨论】:

  • 这与其他一些人的建议基本相同。如果您接受他们的回答会很好,因为他们会花时间帮助您。
  • 你能解释一下fileType == this的工作原理吗
  • 这不起作用。您已经创建了枚举的实例?因为你写的是fileType.in 而不是FileType.in。否则,函数也需要是静态的,然后“this”就像 Rajat 指出的那样不起作用。
  • @Rajat @​​Hasen fileType 是您要针对一种或多种文件类型检查的类的实例(此处为CSV、TXT、FIXED_LENGTH)。由于它是一个实例,in() 方法不是静态的,可以使用this。
【解决方案4】:

添加一个不同的例子:

public class JavaApplication {

    public enum CustomerStatus {
        ACTIVE("Active"),
        DISCONNECTED("Disconnected"),
        PENDING("Pending"),
        CANCELLED("cancelled"),
        NEW("new");

    }

    public static void main(String[] args) {
        EnumSet<CustomerStatus> setA = EnumSet.of(CustomerStatus.ACTIVE, CustomerStatus.NEW);
        EnumSet<CustomerStatus> setB = EnumSet.of(CustomerStatus.PENDING, CustomerStatus.CANCELLED);
        if (setA.contains(CustomerStatus.ACTIVE)) {
            System.out.println("ACTIVE : customer active");
        }
        if (setB.contains(CustomerStatus.ACTIVE)) {
            System.out.println("ACTIVE: Customer is no longer active");
        }
        if (setB.contains(CustomerStatus.CANCELLED)   {
            System.out.println("CANCELLED: Customer is no longer active");
        }

    }
}


**Output**:
ACTIVE : customer active
CANCELLED: Customer is no longer active

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多