How do you create a class of enums without a instance variable? - java

I have a class with a list of enums, The enums are passed to a constructor and updated to the toString, but I am not allowed to have an instance variable on the class (part of the requirement). How can I make the enums output like the String without adding an instance?
public enum Other {
GAME_BOY("Game Boy"), MACBOOK("Macbook Pro"), IPHONE("iPhone XS"), LAPTOP("Laptop");
private final String product; //can't have instance variable
private Other(String passed) {
this.product = passed;
}
#Override
public String toString() {
return product;
}
}

You can override toString() for each element:
public enum Other {
GAME_BOY {
#Override public String toString() { return "Game Boy"; }
},
MACBOOK { ... },
...
}
See this code run live at IdeOne.com.

Alternatively, you can put a switch statement in the toString method:
#Override
public String toString() {
switch (this) {
case GAME_BOY:
return "Game boy";
case MACBOOK:
return "Macbook Pro";
...
}
}

How about the following:-
public enum Other {
GAME_BOY, MACBOOK, IPHONE, LAPTOP;
#Override
public String toString() {
switch(this) {
case GAME_BOY:
return "Game Boy";
case MACBOOK:
return "Macbook Pro";
case IPHONE:
return "iPhone XS";
case LAPTOP:
return "Laptop";
default:
return null;
}
}
public static void main(String[] args) {
System.out.println("The value of the other is " + Other.GAME_BOY.toString());
}
}

Enhanced switch
The accepted Answer by Williamson provides code that can be improved in Java 14 and later. The enhanced switch statement can prevent the problem of missing any of the enum objects in your list of switch cases. See: JEP 361: Switch Expressions.
The new syntax is also terse, easier to read.
Using the new approach looks like this:
package work.basil.example;
public enum Device
{
GAME_BOY, MACBOOK, IPHONE, LAPTOP;
#Override
public String toString ( )
{
return switch ( this )
{
case GAME_BOY -> "Game boy";
case MACBOOK -> "Macbook Pro";
case IPHONE -> "iPhone XS";
case LAPTOP -> "Laptop";
};
}
}
Now go back and add a new type of device, such as WATCH.
GAME_BOY, MACBOOK, IPHONE, LAPTOP, WATCH;
The compiler will flag your switch statement as incorrect. You will see a message like:
the switch expression does not cover all possible input values
Add the additional case in your switch, thereby satisfying the compiler. Then sleep well knowing a nasty bug was averted.
case WATCH -> "Watch";
Example usage:
// Example usage.
public static void main ( String[] args )
{
for ( Device device : Device.values() )
{
System.out.println( "device = " + device );
}
}

Related

How to dynamically call static nested classes?

I have the following java code:
...
public final class Constants {
...
public static class Languages {
...
public static class en_US {
public static final String VALIDATION_REGEX = "[a-zA-Z-' ]+";
...
}
public static class en_GB {
public static final String VALIDATION_REGEX = "[a-zA-Z-' ]+";
...
}
}
...
}
My problem is as follows:
I receive a text and a language, and I have to check, whether that text is written only with valid alphabetic characters of that given language.
My code so far is as follows:
...
public boolean isContentValid(String content, String language) {
Boolean isCorrect = false;
switch (language) {
...
case "en_US":
isCorrect = content.matches(Constants.Phrases.en_US.VALIDATION_REGEX);
break;
case "en_GB":
isCorrect = content.matches(Constants.Phrases.en_GB.VALIDATION_REGEX);
break;
...
default:
isCorrect = false;
}
return isCorrect;
}
...
This is fine and works, but as I add languages to my application, I will have to add more and more cases to my switch.
And I was wondering if in Java there is a way to dynamically name a static nested class, something like:
Constants.Phrases[language].VALIDATION_REGEX
So my above code could be something like:
...
public boolean isContentValid(String content, String language) {
return content.matches(Constants.Phrases[language].VALIDATION_REGEX);
}
...
Thank you, and sorry if this is something super easy.
I am a JavaScript developer, and just learning Java.
Looking at you use case maybe this is a better approach:
public enum Language {
en_US("engUS_reg"),
en_GB("engGB_reg");
private final String regex;
Language(String regex) {
this.regex = regex;
}
public String getRegex() {
return regex;
}
}
And using this enum class write your method as follows:
public boolean isContentValid(String content, String language) {
return content.matches(Language.valueOf(language).getRegex());
}
You could use an enum for something like this.
"An enum can, just like a class, have attributes and methods. The only difference is that enum constants are public, static and final (unchangeable - cannot be overridden)." - [w3][1]
public enum Languages {
EN_US {
#Override
public String toString() {
return "[a-zA-Z-' ]+";
}
},
EN_GB {
#Override
public String toString() {
return "[a-zA-Z-' ]+";
}
},
}
And then you can access these values like this
Languages.valueOf("EN_US");
As mentioned by #Pshemo you could avoid a class based approach entirely and use an implementation of Map if you want something a little more lightweight
[1]: https://www.w3schools.com/java/java_enums.asp#:~:text=An%20enum%20can%2C%20just%20like,but%20it%20can%20implement%20interfaces).

Make code cleaner by making a method that can accept an enum

So currently, I have some code, that is extremely messy and does the opposite of following dry rules. This is killing me internally, and I would love to fix it, if I knew how.
I have a class called Commands, this have two enums in it. Subs, and Options. What I would like to do, is make a method, such as this one here:
public void makeTab(String args, List<String> command, Commands type) {
if (args.equals("")) {
for (Commands.type commd : Commands.type.values()) {
command.add(commd.name().toLowerCase());
}
} else {
for (Commands.type commd : Commands.type.values()) {
if (commd.name().toLowerCase().startsWith(args)) {
command.add(commd.name().toLowerCase());
}
}
}
}
Then, if that method actually worked like I wanted it to, I could then do this.
List<String> command = new ArrayList<>();
switch (args.length) {
case 1:
makeTab(args[0], command, Subs);
break;
case 2:
makeTab(args[1], command, Options);
break;
}
Very sadly though, as you should be able to tell, this doesn't work, specifically because of the "Commands type" bit in the method. The problem is, I don't know what to put there to work, I've tried "Class type", "enum type", "Enum type". So, because of this catastrophe, my code is currently looking like this.
List<String> comd = new ArrayList<>();
switch (args.length) {
case 1:
if (args[0].equals("")) {
for (Commands.Subs commd : Commands.Subs.values()) {
comd.add(commd.name().toLowerCase());
}
} else {
for (Commands.Subs commd : Commands.Subs.values()) {
if (commd.name().toLowerCase().startsWith(args[0])) {
comd.add(commd.name().toLowerCase());
}
}
}
break;
case 2:
if (args[1].equals("")) {
for (Commands.Options commd : Commands.Options.values()) {
comd.add(commd.name().toLowerCase());
}
} else {
for (Commands.Options commd : Commands.Options.values()) {
if (commd.name().toLowerCase().startsWith(args[1])) {
comd.add(commd.name().toLowerCase());
}
}
}
break;
}
tl;dr I'm trying to make the last code block cleaner by making a method for the if, else.
Rather than taking values yourself, have the caller pass values() to you:
public void makeTab(String args, List<String> command, Enum[] values) {
for (Enum commd : values) {
String lowerName = commd.name().toLowerCase()
if (lowerName.startsWith(args)) {
command.add(lowerName);
}
}
}
The caller would invoke your method as follows:
makeTab(args, command, Options.values());
makeTab(args, command, Subs.values());
Note that there is no need to check args to be an empty string, because when args is empty, startsWith(args) returns true for any String value.

Ensure every enum value is used

If I´m using an enum to determine the type of a task.
public enum TaskType {
TYPE_ONE("Type1"),TYPE_TWO("Type2"),TYPE_THREE("Type3");
private final String type;
private StageType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
how can I assure at one point in my Application
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
}
that every enum value is used?
I mean if I need to add a new TYPE_FOUR someday, I´d need to find every place in my code where I used the enum, so I ask myself if there is a better way so that I either avoid the enum and use some other concept or that I can ensure that every value of the enum is used in that piece of code.
There are findbugs type tools for doing that but you could consider removing the if-then-else completely and put the processing inside the enum. Here, adding a new TYPE_FOUR will force you to write it's doProcessing() method.
public interface DoesProcessing {
public void doProcessing();
}
public enum TaskType implements DoesProcessing {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
},
TYPE_FOUR("Type4") {
// error: <anonymous com.oldcurmudgeon.test.Test$TaskType$4> is not abstract and does not override abstract method doProcessing() in DoesProcessing
};
private final String type;
private TaskType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
public void test() {
DoesProcessing type = TaskType.TYPE_TWO;
type.doProcessing();
}
If you would prefer an abstract method then this works:
public enum TaskType {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
};
private final String type;
private TaskType(String type) {
this.type = type;
}
// Force them all to implement doProcessing.
public abstract void doProcessing();
#Override
public String toString() {
return type;
}
}
You could put the process method as an abstract method in TaskType, and then override it in every task in the enum. What would probably be a better idea is if you create an interface, something like:
public interface Task {
void process();
}
Then you either let your enum implement this interface. Or, probably better, you create concrete classes implementing this interface. One class for each of your task types.
I think you are saying that you are wanting the compiler to tell you that all of the enum's values are considered.
Unfortunately, Java doesn't support that.
You might think that you could write something like this:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
}
// not reachable ... no return required
}
... and rely on the compiler to tell you if you left out one of the enum values in the switch cases.
Unfortunately, it doesn't work!! The above is a compilation error anyway. According to the JLS reachability rules, the switch statement needs a default: arm for that method to be valid. (Or you can add a return at the end ...)
There is a good reason for this oddity. The JLS binary compatibility rules say that adding a new value to an enum is a binary compatible change. That means that any code with switch statement that switches on an enum needs to still remain valid (executable) code after the addition of enum values. If method was valid to start with, it can't become invalid (because there is a return path with no return statement) after the binary compatible change.
In fact, this is how I would write the code above:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
default:
throw new AssertionError("TaskType " + t + " not implemented");
}
// not reachable ... no return required
}
This doesn't pretend to be compile-time safe, but it is fail-fast, and it doesn't involve bad OO design.
AFAIK you can't do it "automatically".
To minimize the risk of forgetting to add an if/case for new value you could have one "service" class for each enum value and a factory which provides a specific service for enum value.
E.g. instead of:
void methodA(TaskType type) {
doSth();
switch(type) {
case TYPE_ONE:
foo1();
break;
case TYPE_TWO:
foo2();
break;
...
}
}
void methodB(TaskType type) {
doSthElse();
switch(type) {
case TYPE_ONE:
bar1();
break;
case TYPE_TWO:
bar2();
break;
...
}
}
do:
interface Service {
foo();
bar();
}
class ServiceFactory {
Service getInstance(TaskType type) {
switch(type) {
case TYPE_ONE:
return new TypeOneService();
case TYPE_TWO:
return new TypeTwoService();
default:
throw new IllegalArgumentException("Unsupported TaskType: " + type);
}
}
}
And then the methods above can be rewritten as follows:
void methodX(TaskType type) {
doSth();
ServiceFactory.getInstance(type).foo();
}
This way you have only one point where you have to add handling of new enum value.
HashMap<String, Integer> hm=new HashMap<String, Integer>();
...
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
hm.put(TaskType.TYPE_ONE, 1)
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
hm.put(TaskType.TYPE_TWO, 1)
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
hm.put(TaskType.TYPE_THREE, 1)
}
...
for (TaskType t : TaskType.values()) {
if(hm.get(t)!=1)
// Trigger the alarm
}
You can even count the times the element was count if you need it
You can do swich case on the enum, and fail if the default is hit:
switch(taskType ){
case TYPE_ONE: ... break;
case TYPE_TWO: ... break;
case TYPE_THREE: ... break;
default:
throw new IllegalStateException("Unsupported task type:"+taskType);
}

How to call a method whose name is the value of a string variable in java?

This is the code of the method that I want to simplify. The method name I call of SerializedExpFamMixture class is exactly the value of "model", my question is how to assign the value of "model" directly as the name of the method instead of using "if" to determine which method I should call. Since by using "if", I need to list all the possible values of "model" and judge which method I should use.
Thank you very much for help. I am new to java.
public static SerializedExpFamMixture RateMtxModel(String model)
{
SerializedExpFamMixture result=new SerializedExpFamMixture();
if(model=="kimura1980()")
result=SerializedExpFamMixture.kimura1980();
if(model=="accordance()")
result=SerializedExpFamMixture.accordance();
if(model=="pair()")
result=SerializedExpFamMixture.pair();
return result;
}
One way you can approach this is to use Reflection:
Method method = myClass.getClass().getMethod("doSomething", null);
method.invoke(myClass, null);
Since you are new to Java, it's time for some general pointers:
In Java, we usually name our methods with camelCase, so the first letter is lower case.
Also, in Java we usually leave the opening curly-bracket on the same line as the code (no newline).
Always use final on your variables. At least your parameters. That way you won't overwrite it, and thus won't have to try to figure out which value it actually has at runtime.
Use curly-brackets! Please!
The result variable is not actually needed.
Use the equals-method to compare Strings.
If you only want one result, use else-if
Fixing these things, your method looks like this:
public static SerializedExpFamMixture rateMtxModel(String model) {
if (model.equals("kimura1980()")) {
return SerializedExpFamMixture.kimura1980();
} else if (model.equals("accordance()")) {
return SerializedExpFamMixture.accordance();
} else if(model.equals("pair()")) {
return SerializedExpFamMixture.pair();
}
return new SerializedExpFamMixture();
}
Next, let's look at what you are actually trying to do here. You want to pass some Strings around, and use them as a basis for creating objects. And now, with the advice given here, you will do this using reflection. This does not sound like a very good idea to me. Say you were to go through with this, and this happened:
rateMtxModel("kinura1980");
Small typo, hard to spot, will give unexpected results. If you were actually calling a method the compiler would let you know that you messed up, now you will get no warning (btw did you see both errors in that method call?). The same if someone were to delete the accordance()-method, the compiler would not alert them that this will break the program.
If it was up to be I would just use the static factory-methods in SerializedExpFamMixture directly, but if you have to do it like this (if the task at hand is using a String input to create an object) I would do something like this:
public enum Something {
KIMURA1980("kimura1980()"),
ACCORDANCE("accordance()"),
PAIR("pair()");
private final String stringValue;
private Something(final String stringValue) {
this.stringValue = stringValue;
}
public static Something fromString(final String string) {
for (final Something something : values()) {
if (something.stringValue.equals(string)) {
return something;
}
}
return null;
}
}
public static SerializedExpFamMixture rateMtxModel(final String model) {
if (model == null) {
throw new IllegalArgumentException("model is null!");
}
final Something something = Something.fromString(model);
if (something == null) {
return new SerializedExpFamMixture();
}
switch(something) {
case KIMURA1980:
return SerializedExpFamMixture.kimura1980();
case ACCORDANCE:
return SerializedExpFamMixture.accordance();
case PAIR:
return SerializedExpFamMixture.pair();
default:
return new SerializedExpFamMixture();
}
}
This way, the one place where you will use the Strings is in the enum, the rest of the code will use the enum constants and thus have the safety of the compiler to rely on.
One could also leave the linking between operation and String to the enum, like this:
interface Operation<T> {
public T run();
}
public enum Something {
KIMURA1980("kimura1980()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.kimura1980();
}
}) ,
ACCORDANCE("accordance()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.accordance();
}
}),
PAIR("pair()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.pair();
}
}),
DEFAULT(null, new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return new SerializedExpFamMixture();
}
});
private final String stringValue;
private final Operation<SerializedExpFamMixture> operation;
private Something(final String stringValue, final Operation<SerializedExpFamMixture> operation) {
this.stringValue = stringValue;
this.operation = operation;
}
public static Something fromString(final String string) {
if (string != null) {
for (final Something something : values()) {
if (string.equals(something.stringValue)) {
return something;
}
}
}
return DEFAULT;
}
public SerializedExpFamMixture getCorrespondingSerializedExpFamMixture() {
return operation.run();
}
}
With this setup in the enum (I think the Operation-part can be trimmed out with Java8), the method will be as simple as:
public static SerializedExpFamMixture rateMtxModel(String model) {
return Something.fromString(model).getCorrespondingSerializedExpFamMixture();
}
Use reflection, but you need to consider a few things:
Bug alert! Comparing Strings using == doesn't work as expected in java - use .equals() instead. However, the solution below bypasses that problem
For the general case, which includes methods not visible to the invoker, you need to consider accessibility, both in finding the method and invoking it
You don't need the result variable, and even if using your code, don't need to initialize it
Try this:
String methodName = model.replace("(", "").replace(")", "");
try {
// getMethod() returns only public methods, getDeclaredMethod() returns any visibility
Method method = SerializedExpFamMixture.class.getDeclaredMethod(methodName);
// if the method is not guaranteed to be visible (eg public) you need this:
method.setAccessible(true);
return (SerializedExpFamMixture) method.invoke(null); // how to invoke on the class object
} catch (Exception forBrevity) {
return new SerializedExpFamMixture();
}

How to use enum with values in Java

When I try to use enum to store: "=", ">", "<", etc, I have:
public static enum DataValueModifier {
EQUAL("="),
GREATER_THAN(">"),
GREATER_EUQAL(">="),
LESS_THAN("<"),
LESS_EQUAL("<="),
APPRROXIMATE("~"),
NOT_DETERMINED("ND");
private String value;
private DataValueModifier(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
How do I use it when I try to compare a string to see if it contains a "=" sign, should I do:
if (dataValue.contains(DataValueModifier.EQUAL.getValue())) {
...
}
I understand using enum is the better practice here, but this just looks silly...
Thanks,
David
If you defined a method boolean containedIn(String str) in your enum and imported your enum values of interest (in this case EQUAL), usage would look like:
if (EQUAL.containedIn(dataValue)) {
...
}
First of all, I'd move the "contains" method (or the equivalent of it) to the enum itself by defining an isModifier method.
public static enum DataValueModifier {
...
public boolean isModifier( String modifierString )
{
return modifierString != null && value.equals(modifierString);
}
}
Then, your code looks like this instead:
if (DataValueModifier.EQUAL.isModifier(dataValue))
{
//...
}
But, more importantly, why are you using dataValue instead of the enum in the first place? If you are getting command line input or something or parsing a string equation and then need to figure out the expression I guess I understand. But if you have control of the code then you should just start with the enum and you'll be able to say
if ( dataValueEnum == DataValueModifier.EQUAL ) {
{
//...
}
I'd also consider adding a static method to the enum that converts a given string to the correct enum value. It's not quite as efficient, perhaps, but unless you really care about efficiency it will make your code much cleaner. So add this method to your enum:
public static DataValueModifier toDataValueModifier( String dataValue ) {
if( EQUAL.isModifier( dataValue ) {
return EQUAL;
} else if( GREATER_THAN.isModifier( dataValue ) {
return GREATER_THAN;
} else if...
// Do this for all possible values
} else {
return UNKNOWN;
// Also, add an UNKNOWN to your list of enum values.
}
}
The isModifier and the toDataValueModifier methods might add a bit of ugly code to your DataValueModifier enum, but all your other code will look great. You can now do something like this:
DataValueModifier dataValueEnum = DataValueModifier.toDataValueModifier(dataValue);
if (dataValueEnum == DataValueModifier.EQUAL) {
...
}
or even
switch( DataValueModifier.toDataValueModifier(dataValue) ) {
case EQUAL:
// ...
break;
case GREATER_THAN:
// ...
break;
case GREATER_EQUAL:
// ...
break;
// ... define all the cases you want
case UNKNOWN:
default:
// ...
}
I like to use a static import in these cases.
package mypackage;
public enum DataValueModifier
{
//your enum code
}
then...
import static mypackage.DataValueModifier.*;
public MyClass
{
// code blah blah blah
public void doIt()
{
// more code blah blah
if (dataValue.contains(EQUAL.getValue()))
{
//...
}
}
}
It's a little nicer.

Categories