Check enum for multiple values - java

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

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!

Adding a different example:
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

Related

Best way execute code according enum value

The following code is an example of my problem.
I would like to simplify the code without having to repeat the call for the same methods, on different switch statements.
public void simulate(String given, Status status) {
switch (status){
case A:
simulateA(given);
break;
case B:
simulateA(given);
simulateB(given);
break;
case C:
simulateA(given);
simulateB(given);
simulateC(given);
break;
}
PS 1: The order of the calling methods matters!
PS 2: I am not looking for another way of doing the switch, I am looking for another way of modelling the problem, maybe using some kind of class composition with the methods.
I do not know the nature of your enum but if you have many simulation calls you could forgo the switch statement and do it like this. But there is nothing wrong with your current approach. This would also change slightly if your methods were static and not instance. The one advantage of this is that it has the potential to scale.
There are many other ways to to this. You could have a list of method references and the enum arguments could be variable arrays of which methods to call by index.
public class Simulations {
static List<BiConsumer<Simulations, String>> sims =
List.of(Simulations::simulateA, Simulations::simulateB,
Simulations::simulateC);
enum Status {
A(1), B(2), C(3);
private int val;
private Status(int v) {
this.val = v;
}
public int getVal() {
return val;
}
}
public static void main(String[] args) {
Simulations simulation = new Simulations();
simulation.simulate("A", Status.A);
System.out.println();
simulation.simulate("B", Status.B);
System.out.println();
simulation.simulate("C", Status.C);
}
public void simulate(String given, Status status) {
for (int i = 0; i < status.getVal(); i++) {
sims.get(i).accept(this, given);
}
}
public void simulateA(String s) {
System.out.println(s);
}
public void simulateB(String s) {
System.out.println(s);
}
public void simulateC(String s) {
System.out.println(s);
}
}
In this case, the order of simulations always cascades "downwards", e.g. Simulating an B is simulating an A plus some extra's. This matches an inheritance pattern, e.g. a Mammal is an Animal with some extras. Thus, letting simulations inherit from each other fixes the pattern:
interface Simulation
{
void simulate( final String given );
}
class ASimulation implements Simulation
{
#Override
public void simulate( String given )
{
// simulate this given!
}
}
class BSimulation extends ASimulation
{
#Override
public void simulate( String given )
{
super.simulate( given );
// simulate this given some more!
}
}
class CSimulation extends BSimulation
{
#Override
public void simulate( String given )
{
super.simulate( given );
// simulate this given even more!
}
}
Note that this is fragile, as all inheritance trees are. Another solution can be achieved with composition and delegation. This is called a chain:
class LeafSimulation
implements Simulation
{
#Override
public void simulate( String given )
{
// simulate this given!
}
}
class ChainedSimulation
implements Simulation
{
private final Simulation delegate;
ChainedSimulation( final Simulation delegate )
{
this.delegate = delegate;
}
#Override
public void simulate( String given )
{
delegate.simulate( given );
// simulate this given some more!
}
}
To instantiate the chain, use the following order:
final var aSimulation = new LeafSimulation();
final var bSimulation = new ChainedSimulation( aSimulation );
final var cSimulation = new ChainedSimulation( bSimulation );
This code approaches the problem statement more naturally and eliminates the repetition, but it is not concise.
Once you have set up a mapping of status values to method calls, you can use a SortedSet or EnumSet.range to get the enum values after a particular value:
Map<Status, Consumer<String>> simulators = new EnumMap<>(Map.of(
Status.A, this::simulateA,
Status.B, this::simulateB,
Status.C, this::simulateC));
if (!simulators.keySet().equals(EnumSet.allOf(Status.class))) {
throw new RuntimeException(
"Not all Status values have simulators defined.");
}
// ...
SortedSet<Status> all = new TreeSet<>(EnumSet.allOf(Status.class));
Collection<Status> remainingValues = all.tailSet(status);
// Or:
//Status[] allStatuses = Status.values();
//Status lastStatus = allStatuses[allStatuses.length - 1];
//Collection<Status> remainingValues = EnumSet.range(status, lastStatus);
for (Status s : remainingValues) {
simulators.get(s).accept(given);
}
Another option to consider, which avoids switch / if. Declare a map of actions per Status value which can be used with a getOrDefault lookup default for unhandled values:
Consumer<String> simA = this::simulateA;
Map<Status, Consumer<String>> actions = new EnumMap<>(Map.of(
Status.A, simA,
Status.B, simA.andThen(this::simulateB),
Status.C, simA.andThen(this::simulateB).andThen(this::simulateC)
));
actions.getOrDefault(status, s -> {}).accept(given);
If you want to guard against missing / unhandled mappings you should validate the map (as in #VGR answer) or swap the no-operation default with an exception handler:
actions.getOrDefault(status,
s -> { throw new RuntimeException("Missing action for status: "+status); }
).accept(given);
Assuming your first status is A you can do something like this:
public void simulate(String given, Status status) {
if (status != Status.A) {
int indexOfStatus = status.ordinal();
simulate(given, Status.values()[indexOfStatus - 1]);
}
switch (status){
case A:
simulateA(given);
break;
case B:
simulateB(given);
break;
case C:
simulateC(given);
break;
// here you still need to put all your "simulateX" calls but without repetitions
}
}
you don't need to write simulateA(given) to all your cases, just moved it to top
public void simulate(String given, Status status) {
simulateA(given);
switch (status){
case C:
simulateC(given);
case B:
simulateB(given);
break;
case A:
break;
}}
You can try the fallthrough mechanism of switch statement. refer to this
In your example, the code can be(not tested):
Edited:
public void simulate(String given, Status status) {
switch (status){
case C:
simulateC(given);
case B:
simulateB(given);
case A:
simulateA(given);
}
}
Original(Wrong):
public void simulate(String given, Status status) {
switch (status){
case A:
simulateA(given);
case B:
simulateB(given);
case C:
simulateC(given);
}
}
When the reader has the fallthrough concept in mind, the code above is cleaner and easier to read than the code in question. But that is not always the case. My recommendation would be to restructure your code so as to eliminate both the repetitive calls and the fallthroughs.

Is it possible to restrict switch to use particular cases only in kotlin/JAVA?

Is it possible to restrict switch for using particular case.
Here is my scenario :
class XYZ {
public static final String DEFAULT = "DEFAULT";
public static final String BIG_TEXT = "BIG_TEXT";
public static final String BIG_PICTURE = "BIG_PICTURE";
public static final String CAROUSEL = "CAROUSEL";
public static final String GIF = "GIF";
#Retention(RetentionPolicy.SOURCE)
#StringDef({DEFAULT, BIG_TEXT, BIG_PICTURE, CAROUSEL, GIF})
public #interface NotificationStyle {}
#NotificationStyle
public String style() {
if (CollectionUtils.isNotEmpty(carouselItems)) {
return CAROUSEL;
}
if (CollectionUtils.isNotEmpty(gifItems)) {
return GIF;
} else {
return DEFAULT;
}
}
}
So here I have define one StringDef interface and restricting style() just to return #NotificationStyle specified values and here is my switch case
// Some other class
XYZ obj = new XYZ()
switch (obj.style()) {
case XYZ.BIG_PICTURE:
//Something something
break;
case XYZ.BIG_PICTURE:
//Something something
break;
case "Not available to execute":
//Something something
break;
default : //Something something
}
I know obj.style() will only return restricted values but I want to somehow restrict switch case to even provide this case here
case "Not available to execute":
//Something something
break;
As this will be unreachable code always.
*Please do not look for the code and syntax , just looking for concept here.
Thanks.
You're doing a switch over a String, right? That's why you can, of course, add cases, that won't really happen (like "Not available to execute"). Why don't you just change your possible Strings to an enum and make obj.style return a constant from that enum? This is how you can restict those Strings.
fun style(): XYZValues {
if (true) {
return XYZValues.BIG_TEXT
}
return XYZValues.DEFAULT
}
enum class XYZValues(desc: String) {
DEFAULT("DEFAULT"),
BIG_TEXT("BIG_TEXT")
//more }
}
fun main(args: Array<String>) {
when (style()) {
XYZValues.BIG_TEXT -> println("1")
XYZValues.DEFAULT -> println("2")
}
}

Java casting interface but using object methods

I have a question on how to call an objects base member when instantiated through an interface.
Suppose I have the following interface and concrete classes in a framework I am trying to build:
public interface UsedClass {
public boolean getBool();
}
public class User implements UsedClass {
private String userName;
private String userRole;
public User(String userName, String userRole){
this.userName = userName;
this.userRole = userRole;
}
public boolean getBool() {
// some code
}
public int getUserName() {
return userName;
}
public int getUserRole() {
return userRole;
}
And an implementing class:
public class Run implements UsedClass {
private String runName;
private int runNumber;
public Run(String runName, int runNumber){
this.runName = runName;
this.runNumber = runNumber;
}
public boolean getBool() {
// some code
}
public String getRunName() {
return runName;
}
public int getRunNumber() {
return runNumber;
}
}
But I cannot put methods getRunName() or getUserRole() into the interface!
The end goal is to create a FactoryClass to handle the objects passed from a database GUI.
I would like to know if there is a better way then using class reference be able to safely call methods of Run or User such as:
public class EntityFactory {
public static Object getValueAt(int rowIndex, int columnIndex, UsedClass usedClass) {
if (usedClass.getClass().getSimpleName().equals("User")) {
switch (columnIndex) {
case 0:
return ((User) usedClass).getUserName();
case 1:
return ((User) usedClass).getUserRole();
default:
return null;
}
} else if (usedClass.getClass().getSimpleName().equals("Run")) {
switch (columnIndex) {
case 0:
return ((Run) usedClass).getRunName();
case 1:
return ((Run) usedClass).getRunNumber();
default:
return null;
}
}
I have read several SO posts
type casting when objects are of interface references in Java and Java cast interface to class
where it is implied that reference casting is not advised, but since I cannot put all methods into the interface, what would be advised?
static interface ColumnSource<T> {
String getColumn(T value, int index);
}
static Map<Class, ColumnSource> map = new HashMap();
static {
map.put(User.class, new UserNameAndRoleSource<User>() {
public String getColumn(User user, int index) {
switch (index) {
case 0: return user.getUserName();
case 1: return user.getUserRole();
default: throw new RuntimeException();
}
}
});
map.put(Run.class, new ColumnSource<Run>() {
public String getColumn(Run run, int index) {
switch (index) {
case 0: return run.getRunName();
case 1: return run.getRunNumer();
default: throw new RuntimeException();
}
}
});
}
public static Object getValueAt(int rowIndex, int columnIndex, Object o) {
Class type = o.getClass();
ColumnSource source = map.get(type);
if (source == null) throw new RuntimeException(type.getName() + " not supported");
return source.getColumn(o, columnIndex);
}
You should use instanceof rather than looking at the simpleName of the class.
Beyond that you are correct. You either need to have an interface containing the common methods which you can then call them in or you need to identify that the object is an instance of a specific class and then do the cast and make the method call.
You could consider using a Map<Class<? extends UsedClass>, Map<Integer, Function<___>>> handlers.
Then your processing would be
handlers.get(usedClass.getClass()).get(columnIndex).apply(usedClass);
Obviously you would want to consider how to handle the unexpected class/index case. The inner Map<Integer,... could potentially be a List<...> depending on how it is being used.
Two things:
if at all, you use instanceof instead of string / class name comparison
you build your interfaces / classes to be helpful. They are the base of all the things you are doing. If you start with broken abstractions, you are broken. Simple as that.
What I mean is: if there is "common" behavior; then you should express that using a common interface. If not, you start your efforts on an already broken base; and you will be need to create "creative workarounds" all over the place in order to fight the symptoms of that disease.
Maybe one small solution could be to have at least multiple interfaces, like
interface UsedClass { ...
interface SpecialUsedClassA extends UsedClass { ...
interface SpecialUsedClassB extends UsedClass { ...
than you can at least return UsedClass instead of Object.

Function with toggle options

I've made a basic function to check a password complies with various business rules. Has an upper case character, has a number etc.
I'd like to make this function more flexible and configurable by toggling these options on and off as desired. The only way I can think of to do this is as so:
public static boolean isPasswordValid(String pwd, boolean checkUpper, boolean checkLower, boolean checkNum) {
boolean hasUppercase = !pwd.equals(pwd.toLowerCase(Locale.getDefault()));
boolean hasLowercase = !pwd.equals(pwd.toUpperCase(Locale.getDefault()));
boolean hasNumeric = pwd.matches(".*\\d+.*");
boolean isValid = false;
if(checkUpper){
if(hasUppercase) {
isValid = true;
}else{
return isValid;
}
}
return isValid;
}
I feel like there is a much better method, using Enums or something. I'd like to be able to pass in the password and just one extra parameter to act as a flag to enable various checks. Inevitably I'll need to add more as time goes on.
If I were to use enums, by my way of thinking, I'd have to define one eNum for every possible case. i.e. upper, upper_and_lower, upper_and_numeric. Which would get very complex if I had to add in more options.
Any ides and suggestions would be most welcome. Thanks.
You can use EnumSet, which is a specialized set for enums.
public static enum Validation {
UPPER, LOWER, DIGIT //etc.
}
public static boolean isPasswordValid(String pwd, EnumSet<Validation> validations) {
//...
}
Then, you can use any combination of validations by adding necessary values to the set. Example:
EnumSet<Validation> validation = EnumSet.of(Validation.UPPER, Validation.LOWER);
if (isPasswordValid(pass, validation)) {
//...
}
You could do it with regex:
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$
You validate for password with all three combinations (number, upper, lower case alphabets)
String pwd = "aaaaaaabbbbCCCC43333333222111";
if (pwd.matches("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*$")) {
System.out.println("It has all three combinations");
} else {
System.out.println("Invalid password");
}
Output:
It has all three combinations
Less Simple, but really flexible, using method chaining:
public abstract class Clause {
public abstract boolean match(string value);
}
public final class UpperCaseClause extends Clause {
#Override
public boolean match(string value) {
return !value.equals(value.toLowerCase(Locale.getDefault()));
}
}
public final class LowerCaseClause extends Clause {
#Override
public override boolean match(string value) {
return !value.equals(value.toUpperCase(Locale.getDefault()));
}
}
public final class NumericClause extends Clause {
#Override
public override boolean match(string value) {
return value.matches(".*\\d+.*");
}
}
public final class Validator {
private List<Clause> clauses;
public Validator() {
clauses = new ArrayList<Clause>();
}
public Validator addClause(Clause toAdd) {
clauses.add(toAdd);
return this;
}
public boolean valid(string value) {
boolean isValid = true;
for(clause in clauses) {
isValid &= clause.match(value);
if (!isValid) {
break;
}
}
return isValid;
}
}
[... you could create this anywhere and cache it]
Validator allValidator = new Validator().addClause(new UpperCaseClause())
.addClause(new LowerCaseClause())
.addClause(new NumericClause());
[...]
public static boolean isPasswordValid(String pwd, Validator validator) {
validator.valid(pwd);
}
[... then pass in the validator you wish to use]
isPasswordValid(pwd, allValidator);
[...]

enum inheritance, or something similar

I have a string (which is a message) that I get as input and I need to do one of 4 possible things depending on the string
I know that there is eunm.valueOf() option, but I have 4 different enums, each with few possible messages.
looks something like:
public enum first{ONE,TWO,THREE};
public enum second{FOUR,FIVE,SIX};
public enum third{SEVEN,EIGHT,NINE};
public void work(String message){
//Here I want to compare message string to one of the 3 enums
}
is it possible to do this in one method of the enum?
or should I just try to create one, and if I get an exception try the other and so on?
As others have commented, it may be better to think through whether you really need 4 distinct enums.
But if you do, you could have them implement a common interface. Then you can map the input strings to the appropriate enum member, and call its method to accomplish what you want. Something like
public interface SomeInterface {
void doSomething();
};
public enum First implements SomeInterface {
ONE,TWO,THREE;
#Override
public void doSomething() { ... }
};
...
Map<String, SomeInterface> myMap = new HashMap<String, SomeInterface>();
for (First item : First.values()) {
myMap.put(item.toString(), item);
}
...
public void work(String message){
SomeInterface obj = myMap.get(message);
if (obj != null) {
obj.doSomething();
}
}
This assumes that the 4 possible things you want to do correspond to the 4 enums. If not, you can override the method separately for each and any enum member too, e.g.
public enum First implements SomeInterface {
ONE,
TWO {
#Override
public void doSomething() { // do something specific to TWO }
},
THREE;
#Override
public void doSomething() { // general solution for all values of First }
};
Enumerations in Java are full blown classes. Individual values can even override the behavior to meet their needs. It's pretty cool. You can use this to your advantage:
public enum Value implements Worker
{
ONE,
TWO,
THREE
{
#Override
public void doWork(String message)
{
// overrides behavior of base enum
}
},
FOUR,
/* ... */,
NINE;
private final String message;
Value() { this(""); }
Value(String message) { this.message = message; }
public void doWork(String message)
{
if (this.message.equals(message))
{
/* ... */
}
}
}
public interface Worker
{
void doWork(String message);
}
You can create a Map of them all
static final Map<String, Enum> enumMap = new LinkedHashMap<String, Enum>(){{
for(First e: First.values()) put(e.name(), e);
for(Second e: Second.values()) put(e.name(), e);
for(Third e: Third.values()) put(e.name(), e);
}};
Enum e = enumMap.get(name);
What you're really looking for is a aggregation of the other enums. The easiest way to get that is to make a new enum that puts all of those choices in a new enum. Something to this effect:
public enum Combination {
NEWONE(first.ONE), NEWTWO(first.TWO), NEWTHREE(first.THREE),
NEWFOUR(second.FOUR), NEWFIVE(second.FIVE), NEWSIX(second.SIX),
NEWSEVEN(third.SEVEN), NEWEIGHT(third.EIGHT), NEWNINE(third.NINE);
private String contents;
public Combination(first f) {
contents = f.toString();
}
public Combination(second s) {
contents = s.toString();
}
public Combination(third t) {
contents = t.toString();
}
public String toString() {
return contents;
}
}
This will more correctly aggregate the previous enums into a single data structure.
Even given your odd/even example in the comments, I don't feel multiple enums are the way to go here. I would use something like (warning, untested):
public enum Numbers {
ONE("first"), TWO("first"), THREE("first"), FOUR("second"), FIVE("second"), SIX("second"), SEVEN("third"), EIGHT("third"), NINE("third")
private String type;
Numbers(String t) { this.type = t; }
String getType { return this.type; }
}
Then you can use valueOf() to look up the enum element, and getType() to find out which of your three categories it belongs to.
It isn't entirely clear what you are asking, but perhaps you want to define a mapping between strings and constants, like this:
enum Type { FIRST, SECOND, THIRD };
Map<String, Type> mapping = new HashSet<String, Type>(){{
put("ONE", Type.FIRST);
put("TWO", Type.FIRST);
//...
put("NINE", Type.THIRD);
}};
public Type getTypeFromString(String s) {
return mapping.get(s);
}

Categories

Resources