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) {}
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.
Enums can't have multiple value per name.
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.
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.)
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
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".
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With