Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check enum for multiple values

I have an enum FileType

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

FileType fileType = FileType.CSV;

Is there a better (cleaner) way to check fileType for multiple values than the following (like "myString".matches("a|b|c");)?

if(fileType == FileType.CSV || fileType == FileType.TXT || fileType == FileType.FIXED_LENGTH) {}
like image 261
halloei Avatar asked Nov 27 '14 14:11

halloei


People also ask

Can one enum have multiple values?

we should do the following steps to have an enum with different values: Create enum constructor which accepts multiple values. Assign each constructor argument to a member field in the enum definition. Create getter methods so we can access any of the values assigned to a particular enum constant.

Can enum have multiple values python?

Enums can't have multiple value per name.

What is EnumSet in Java?

An EnumSet is a specialized Set collection to work with enum classes. It implements the Set interface and extends from AbstractSet: Even though AbstractSet and AbstractCollection provide implementations for almost all the methods of the Set and Collection interfaces, EnumSet overrides most of them.

What does enum valueOf return?

valueOf. Returns the enum constant of the specified enum type with the specified name. The name must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)


3 Answers

Option 1: Add a boolean field to your enum.

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()) {
    ...
}

Option 2: use an EnumSet. EnumSets use bitfields under the hood, so they are very fast and low memory.

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

Option 3: use a switch, as kocko suggests

like image 145
khelwood Avatar answered Sep 23 '22 17:09

khelwood


Why not use a switch:

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

This does the same as your if statement check, but it's more readable, imho.

But the problem with this code is not the switch or the if/else statement(s). The problem is that it breaks the Open-closed principle.

In order to fix that, I would completely remove the enum and create an interface:

interface FileType {
   boolean isInteresting();
}

Then, for each enum constant we used to have, I would create a separate interface implementation:

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

How does the switch statement change? We used to pass a fileType parameter, on which we checked the value. Now, we will pass an instance of FileType.

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

The advantage of this is that when you introduce a new FileType (which you would introduce as a new enum constant), you don't have to modify the switch/if/else statement to handle the case when this new file type is interesting or not. The code will simply work here without modification, which is the essence of the Open-closed principle: "Open for extensions, closed for modifications".

like image 20
Konstantin Yovkov Avatar answered Sep 19 '22 17:09

Konstantin Yovkov


I ended up writing a method:

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

And then:

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

Nice and clean!

like image 28
halloei Avatar answered Sep 20 '22 17:09

halloei