This week's book giveaway is in the Python forum.
We're giving away four copies of Python Continuous Integration and Delivery and have Moritz Lenz on-line!
See this thread for details.
Win a copy of Python Continuous Integration and Delivery this week in the Python forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
Sheriffs:
  • Devaka Cooray
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Tim Holloway
  • Claude Moore
  • Stephan van Hulst
Bartenders:
  • Winston Gutkowski
  • Carey Brown
  • Frits Walraven

How to call a method, if the enum values match method names  RSS feed

 
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have the following scenario, explained with pseudo code:



Further in the class, outside of the enum, I have methods that mirror the enum values:



Currently I use a switch statement to match the enum value to the user input and then perform the steps required, as follows:



As you can see the steps are the same except for the one method call that matches the enum value.

There are nine enums, resulting in a lengthy switch statement.

Is there a way that I can replace the switch statement with a loop, something like:



This forms part of a menu where I need to call different methods for each menu item.

As recommended here, I am using enums to represent the menu choices:
https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
 
Marshal
Posts: 63391
205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Jay Rex wrote:. . . Is there a way that I can replace the switch statement with a loop, . . .

Yes, but a switch will give you faster execution than a loop and multiple ifs.

I am using enums to represent the menu choices:
https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

The example there is a bit contrived; you wouldn't necessarily create an object just to run a switch. I think the bit about new EnumTest(Day.MONDAY) is overkill. I suggest you stick to the switch however.

On the other hand, remember that your enum constants are full‑blown objects in their own right. They can therefore have methods and can therefore extend themselves. You cannot create a class that extends an enum, but you can create an enum constant that extends its own class. You can give them overridden methods, but you have to use some slightly odd syntax; you have to follow all the overriding methods with a declaration of an abstract method. It is best you see an example: go through the Java® Language Specification and find the example that does arithmetic. I think it is called Operation. Maybe something like that will help, and you can make it very “OO” (=object‑oriented).

[edit]The JLS doesn't actually say that the method delared after the constants has to be abstract.
 
Sheriff
Posts: 5745
148
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I like Campbell's suggestion of methods in the enum.  The link you posted has an example of this: the Planets enum near the bottom.

Just for the record, your switch code example could be written like this:
But I like this way better:
The trick is getting Example.values().  If you're interested, we can discuss it further.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My pseudo code seems to have muddied the question, so here is another attempt:

Ignore all the enum exposition and simply consider the following:

Is there a way to call a method, if you only have the value of a String which has the same value of the name of the method that needs to be called?

Example:



Now that I have access to the stringName, I write something, such as:



The code above would then produce the equivalent of typing the following:

 
Sheriff
Posts: 13155
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To me, this is a design issue, not a technical one. I would consider the possibility of extracting all those methods to their respective enum instances instead so you can use polymorphism properly, like this:

Where actionChosen is the enum value that corresponds to the user's choice.
 
Knute Snortum
Sheriff
Posts: 5745
148
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Is there a way to call a method, if you only have the value of a String which has the same value of the name of the method that needs to be called?


Technically, yes.  It's called Reflection.  But Reflection should normally not be used in a regular (non-utility) application.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:On the other hand, remember that your enum constants are full‑blown objects in their own right. They can therefore have methods and can therefore extend themselves. You cannot create a class that extends an enum, but you can create an enum constant that extends its own class. You can give them overridden methods, but you have to use some slightly odd syntax; you have to follow all the overriding methods with a declaration of an abstract method. It is best you see an example: go through the Java® Language Specification and find the example that does arithmetic. I think it is called Operation. Maybe something like that will help, and you can make it very “OO” (=object-oriented).


I had a look at that example, but if I understand you correctly it would mean moving the logic from the class inside the enum. My class methods are only named the same as the enums for readability. I don't see how that would make sense, as each method is completely different, based on the choice of the user.


Knute Snortum wrote:I like Campbell's suggestion of methods in the enum.  The link you posted has an example of this: the Planets enum near the bottom.


I think this is the same as my answer to Campbell above.


Junilu Lacar wrote:To me, this is a design issue, not a technical one. I would consider the possibility of extracting all those methods to their respective enum instances instead so you can use polymorphism properly, like this:


I don't understand your comment unfortunately.

Knute Snortum wrote:Technically, yes.  It's called Reflection.  But Reflection should normally not be used in a regular (non-utility) application.


This seems like what I was looking for. I'll leave that for another time.

Thank you for all your replies. For now, what makes the most sense is to keep the long switch statement.

 
Campbell Ritchie
Marshal
Posts: 63391
205
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Knute Snortum wrote:. . . Reflection should normally not be used in a regular (non-utility) application.

Reflection is probably most useful for people who write IDEs and that sort of thing. At your stage, you should probably avoid it. Reflection can be error‑prone or evade type‑checking and exception handling.

Jay Rex wrote:My class methods are only named the same as the enums for readability. I don't see how that would make sense, as each method is completely different, based on the choice of the user.

Do you really mean class methods? Remember that class methods are the opposite of instance methods. I don't follow the logic about different methods. What you are trying to do would look something like this in C:-But you can't do that in Java®. You cannot pass a function pointer or anything like that. What you can do in Java® however is pass an object reference and that object has a method.What is wrong with an enum like this?That shows polymorphism localised to individual instances rather than localised to different subclasses. What is wrong with the methods being different from each other? Remember that documentation comments would be an integral part of such an enum. Put the documentation comments before the elements, not in their class bodies.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Do you really mean class methods? Remember that class methods are the opposite of instance methods.


It seems I may not be using the correct terminology. I think I am referring to instance methods.

I am referring to the following types of methods, when I said class methods:


So I currently have the following basic enum inside the class:



Do I understand you correctly that I could call option1() from inside the enum?

Your solution seems ideal, but I would need to keep the index and the menu text and the executeOption method. How would I do that?
 
Campbell Ritchie
Marshal
Posts: 63391
205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Jay Rex wrote:. . . . I think I am referring to instance methods. . . .

Yes, that is an instance method. Carefu about jargon; it must be used correctly, in which case it becomes very precise and very concise. If you say “class method” with the correct jargon, others will know exactly what you mean

. . . I would need to keep the index and the menu text and the executeOption method. How would I do that?

Yes, you can call Options.OPTION1.option(); If you are overriding the methods and using polymorphism, they will all need the same name.
You can get an array of all elements of an enum with one of its methods (I think values()). Look in the JLS, where it tells you which methods you haven't written but are implicitly included in every enum. Yoiu can also use the valueOf() method. You can put the elements as “V”s in a Map.
If you look in the Enum class' documentation, you will find more methods, including ordinal() though they recommend you don't use that one.
 
Campbell Ritchie
Marshal
Posts: 63391
205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
About half an hour ago, it occurred to me that you can create an EnumMap whose “K”s comprise the entire range of elements of your enum and whose “V”s are objects representing an action you want to execute.That has the advantage that you can decide which object you are going to apply the action to, as the program starts. You can even change that while the program is running.
 
Rancher
Posts: 3080
108
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting!

But Junilu's suggestion is also very nice, even possible with some dynamics in it. For instance:
 
Bartender
Posts: 2166
92
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:


I kinda feel that it may not be good for an enum to hold state. Effectively what you have done is change Flup.OPTION1's action throughout the code. Any other class using OPTION1 will get the same action.
I think it's a bad code smell, I may be wrong.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for the replies since my last post, but the suggestions are above my current level of understanding.

I found the following enum syntax inside Head First Java, which seems to be what I need:


I would like to use the format of the code example above, if possible.

Here is my code. It compiles, but it doesn't print the output inside menu1(), nor menu2():


It doesn't seem to matter if I change the access level to public or private, I achieve the same result, which is that the code compiles but never displays menu1(), nor menu2()

Please advise how to correct the above code.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The code above was incorrect. Here is the corrected code, which works:

On lines 50 and 52, input should have been userInput.



Thank you for all the help. The enum constant specific class body has replaced a 40 line switch statement with a single for and if loop.

Please advise any improvements to the code above.
 
Rancher
Posts: 3926
45
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You don't need that second loop, as you already have code in the enum that returns a Menu based on the given index.
You are essentially duplicating code at the moment.
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Dave Tolls wrote:You don't need that second loop, as you already have code in the enum that returns a Menu based on the given index.
You are essentially duplicating code at the moment.


The first loop prints the entire menu.
The second loop calls the appropriate menu method based on user input.

I don't see how I can remove the second loop, as I need to ask for the user input after printing the menu.
 
Marshal
Posts: 6588
443
BSD Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No Jay. Dave is right.

You have this code snippet in your enum:

So it returns a corresponding value (assuming it exists) based on the given input. So what Dave mentioned, the second loop can be simply removed as it does same thing. That would look similar to:
instead of:

Of course you need to take into consideration null case since you return one.

In general, I find your code hard to read. First and main reason is poor formatting (blocks of code crammed to one line).
 
Liutauras Vilda
Marshal
Posts: 6588
443
BSD Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Another question: why index is String? At least in my head, when I think about index, I have in my mind a number, probably a whole number.

I also would have an enum in a separate source file instead of having it in a Test class (even if that's just for test). Otherwise makes it harder to follow the code as really Test class and Menu enum aren't related in any sense.

Also, why you return "null" when option can't be parsed? Wouldn't make more sense to throw an exception as some illegal value managed to slip in after the user entered something wrong?
 
Junilu Lacar
Sheriff
Posts: 13155
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Jay Rex wrote:

Junilu Lacar wrote:To me, this is a design issue, not a technical one. I would consider the possibility of extracting all those methods to their respective enum instances instead so you can use polymorphism properly, like this:

I don't understand your comment unfortunately.


Others like Campbell and Piet have already followed through with the idea so I hope you now understand where I was going with that comment.

Using reflection to achieve what you said is technically possible but in my opinion, that's not the real problem.

What you're basically needing is a way to dispatch or route a user request made interactively. It's essentially the same problem as dispatching a request made via a web service call or an HTTP request and there are many ways this can be solved, from the simple and straightforward (at the cost of flexibility) to the complex but flexible. As a programmer/designer, you have to weigh the costs/benefits of the approach you decide to  use.

Reflection is not the way I would go because it's not very obvious and it creates too much coupling between the method names you use in the program and hard-coded values that are assigned to different parts of the control/dispatch mechanism. It might seem clever but I think it's too clever for its own good and overkill for the problem that you're trying to solve.

In your case, I would probably lean toward simplicity. Here's why:

1. This seems to be a relatively small program with a limited lifetime
2. Given #1, I doubt it would be worth going to all the trouble of using reflection to dispatch the user's choice.
3. Given your relative inexperience, you might want to stick with an approach that you and others can easily understand.

I actually don't like my original suggestion to move the handler methods to specific enum values that much. I prefer designs to be obvious and intuitive. Having enums as action handlers is not an obvious design choice  since enums are rarely used this way.

If you really want to get rid of the long switch statement, which for a simple program that has a limited lifetime isn't that bad, then I would try something like what I show below. This to me is a more obvious design:

On line 20, you set up the routing/dispatch table with different action handlers. Maintaining this code is not difficult: to add a menu option, define a new ActionHandler implementation and then add it to the routingTable. The single-line dispatch call is made on line 30 after the user has entered a valid menu option. This line of code does not have to be changed at all if you add or remove menu options.

Perhaps the only additional refactoring I'd make to the above would be this:
 
Campbell Ritchie
Marshal
Posts: 63391
205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:. . . In your case, I would probably lean toward simplicity. Here's why: . . .

I can think of another reason: a simple solution is less likely to be error‑prone. That is probably an extension of Junilu's reason No 3.
 
salvin francis
Bartender
Posts: 2166
92
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
routingTable can be a map with key as Integer

This way, we can also verify if an action exists
 
salvin francis
Bartender
Posts: 2166
92
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
 
Jay Rex
Ranch Hand
Posts: 56
7
Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:Menu.value(userInput).menuOption();


Thank you, I didn't understand what Dave meant.

Liutauras Vilda wrote:In general, I find your code hard to read. First and main reason is poor formatting (blocks of code crammed to one line).


I read the link in Carey's signature where it spoke about cramming, but Oracle themselves do it so that is why I have done the same.
See: https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9
As we read from left to right, I thought it makes sense to include a block on one line if there is only one statement inside the block. Is that not correct? If not, why would Oracle format their code in a way that is discouraged?

Liutauras Vilda wrote:Another question: why index is String? At least in my head, when I think about index, I have in my mind a number, probably a whole number.


The rationale is that the input is already a String, so just keep it as that.

Liutauras Vilda wrote:I also would have an enum in a separate source file instead of having it in a Test class (even if that's just for test). Otherwise makes it harder to follow the code as really Test class and Menu enum aren't related in any sense.


This is a small project, so almost all the code will be in one file. I will remember that for larger projects.

The reason the class is called Test, is simply my workflow. If I want to convey a problem I am experiencing, I open a file called Test.java and start typing. This seems to be in line with SSCCE, which I read about in Carey's signature.

Junilu Lacar wrote:Using reflection to achieve what you said is technically possible but in my opinion, that's not the real problem.


Until this thread I didn't know Reflection existed, so I won't be using it

Junilu Lacar wrote:If you really want to get rid of the long switch statement, which for a simple program that has a limited lifetime isn't that bad, then I would try something like what I show below. This to me is a more obvious design:


Thank you for showing me that code. It has shown me the further reading I need to do before I understand what you are doing

salvin francis wrote:routingTable can be a map with key as Integer


As above
 
Campbell Ritchie
Marshal
Posts: 63391
205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

salvin francis wrote:routingTable can be a map with key as Integer . . .

. . . and that bring us back to the concept behind the original version of switch, which took ints for all cases.
 
Bartender
Posts: 5635
56
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried to follow this thread and it seems to get more convoluted as it goes on.
  • Why an "enum"? If you want to change what is called for each enum option it no longer behaves as a constant and may pull the rug out from under another section of code that happens to use the same enum.
  • Is this an attempt to do away with a switch, which is slightly verbose but efficient?

  • Anyway, maybe I'm off track here, but this is my stab at it. I've used a List but could have just as well used a Map.
     
    Junilu Lacar
    Sheriff
    Posts: 13155
    219
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Carey Brown wrote:Anyway, maybe I'm off track here, but this is my stab at it. I've used a List but could have just as well used a Map.


    You had me until Runnable. I would have expected something like Consumer instead.
     
    Carey Brown
    Bartender
    Posts: 5635
    56
    Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
     
    Liutauras Vilda
    Marshal
    Posts: 6588
    443
    BSD Linux Mac OS X VI Editor
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Carey Brown wrote:Runnable takes no args and returns void. Perhaps not the best choice?


    I'd think perhaps the intended use of Runnable interface not necessarily would be correct in this case. Runnable interface's implementing class's instance is meant to be passed onto thread and executed by the thread's start() method, and not directly as you specified as a standalone runnable. Anyway, I'm doubted we are talking about the concurrent application here, hence such Junilu's comment. But I'll leave to him to comment what he meant.
     
    Carey Brown
    Bartender
    Posts: 5635
    56
    Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Based on example in "Java 8 in Action", pg 45.
    Could have used (or created) another interface with a no-arg, no-return, definition. Runnable works but has some presumed uses which don't apply in this particular case.
     
    Junilu Lacar
    Sheriff
    Posts: 13155
    219
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Carey Brown wrote:Runnable takes no args and returns void. Perhaps not the best choice?


    Runnable violated POLA for me because of the semantics, much like what others have said in this SO thread: https://stackoverflow.com/questions/23958814/functional-interface-that-takes-nothing-and-returns-nothing

    Maybe define your own functional interface. Procedure or Action maybe.
     
    salvin francis
    Bartender
    Posts: 2166
    92
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Carey Brown wrote:Runnable takes no args and returns void. Perhaps not the best choice?



    Javadoc says
    The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.
     
    salvin francis
    Bartender
    Posts: 2166
    92
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:. . . and that bring us back to the concept behind the original version of switch, which took ints for all cases.


    I agree that a switch statement would be much more efficient. But, I would prefer the Map for flexibility and OO approach. There are good merits for both scenarios.
     
    Junilu Lacar
    Sheriff
    Posts: 13155
    219
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    salvin francis wrote:I agree that a switch statement would be much more efficient.


    Much more? I guess it depends on the scale you're measuring any differences. But this is an interactive program and the difference between the performance of a switch vs. Map vs. any other proposed approach is going to be insignificant, in my opinion. The time it takes to understand the design structure and figure out what you need to do to maintain it is what I would take as the major consideration if you're going to talk about "efficiency" -- I would say in this case, prefer making the maintenance programmer more efficient, not program execution.
     
    salvin francis
    Bartender
    Posts: 2166
    92
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:...I would say in this case, prefer making the maintenance programmer more efficient, not program execution.


    okay.. so we both agree on an OO approach instead of a switch. I mentioned that ("But, I would prefer the Map for flexibility and OO approach") and I even wrote a "ActionController" based code above for it. This was my suggestion as opposed to a switch :
     
    Junilu Lacar
    Sheriff
    Posts: 13155
    219
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I'm not entirely opposed to a switch statement either. OP's original code appeared to have some duplication in it but that probably could have been refactored away without abandoning the switch statement.

    In his 2nd edition of "Refactoring," Martin Fowler writes:

    The point of refactoring isn't to show how sparkly a code base is—it is purely economic. We refactor because it makes us faster—faster to add features, faster to fix bugs.


    If we consider this to be a matter of aesthetics, where nothing is either good or bad but thinking makes it so, we lack any guide but personal taste. I believe, however, that we can go beyond taste and say that the true test of good code is how easy it is to change it. Code should be obvious: When someone needs to make a change, they should be able to find the code to be changed easily and make the change quickly without introducing any errors. A healthy code base maximizes our productivity, allowing us to build more features for our users both faster and more cheaply.


    I don't know if personal taste can be entirely eliminated from the refactoring decisions we make since it seems like what is "obvious" to some isn't obvious to others. Where the line between obviousness and obscurity falls is probably along the same lines as individual experience and we each have our own experience, which also continues to evolve. Whether or not two or more people can agree on what's obvious can probably be predicted by how similar or different their experiences with code are.
     
    Hey cool! They got a blimp! But I have a tiny ad:
    Become a Java guru with IntelliJ IDEA
    https://www.jetbrains.com/idea/
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!