• 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 Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

Enum , providing getInstance() method

 
Ranch Hand
Posts: 1211
Mac IntelliJ IDE
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi all. Ok...tinkering with new JDK features..

Since, enum(s) should have a limited number of instances, does it make sense to provide a (Singleton'ish) getInstance method ?



This method could be useful where the enum instance used depends on a char value in the database for example.

Is there a better way of doing this?

Thanks.
 
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You might mean a reverse mapping, and it makes no sense; your example reverse mapping is specific to your enum type (not all enums have a reverse mapping from a char to the enum type). Also, reverse mappings should be provided with O(1) lookup, not O(n) that is provided by switch/case (one of two fundamental reasons why switch/case should never be used).
 
Sonny Gill
Ranch Hand
Posts: 1211
Mac IntelliJ IDE
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Tony.

The enum type to be used is based on a value of type CHAR(1) in the database.
What is the alternative?
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are a few gotchyas when implementing a reverse mapping with both 1.5 enums and the appropriate alternative prior to 1.5 (which unfortunately is misconceived as a multitude of int or Strings in an interface or class).

Typically, I define a private static class of the enum that contains a Map ,for your case, Map<Character, EnumType>, and lazily initialise it (in a static initialiser for class loader) to the appropriate values (or load them from an external resource if appropriate (the other reason why switch/case is flawed - you cannot do this)).

There is an 'almost example' in JTiger - the difference being it's not a reverse mapping for an enum, but is a public interface (for your enum, it would all be private exception for your public 'getInstance' method). The example is the class org.jtiger.report.html.ResultMappingFactory. This class is included with the source code, which is in the download.

Good luck.
[ July 05, 2005: Message edited by: Tony Morris ]
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Tony]: You might mean a reverse mapping, and it makes no sense; your example reverse mapping is specific to your enum type (not all enums have a reverse mapping from a char to the enum type).

It's true that you can't do this particular type of mapping in general for all enums. However it certainly can be done for this particular mapping. "It makes no sense" makes no sense here, IMO.

In fact, enums already have a reverse lookup built in - the valueOf() method defined in java.lang.Enum. It uses Strings - specifically, it uses the identifiers for the specific values of the enum. So Sonny could do something like this:

Instances can then be looked up easily:

The downside of this is that it forces us to use identifiers which duplicate the database values. This results in a loss of readability if we would have preferred a name like North rather than N. It may also require us to abandon conventional Java naming conventions in order to match the DB values. Still, it may be acceptable to put up with these problems, as it's extremely quick and easy to create the enum in this case - no methods need to be coded at all.

Also, reverse mappings should be provided with O(1) lookup, not O(n) that is provided by switch/case (one of two fundamental reasons why switch/case should never be used).

Actually switch statements are quite capable of providing O(1) lookup - that's what the tableswitch instruction in the JVM is for. Of course, the compiler doesn't bother using a tableswitch for low values of N like 4, as in Sonny's example. The overhead in setting up the table isn't warranted - it's faster to use a lookupswitch. Note that the docs for lookupswitch indicate that it may be faster than O(n), and indeed it's not difficult to imagine that a JVM could do the lookup in O(log(N)) for a lookupswitch, since it basically just requires a binary search. I don't know if the JVM actually does a binary search - maybe there's never been any significant demand for optimization in this area; dunno. (Switch statements aren't very common in Java, as there are usually better alternatives involving polymorphism and/or a Map of some sort.) Regardless, the compiler has several options for implementing switch statements efficiently, and overall it does a pretty good job in this department. There are some cases where it's prohibitive to use a tableswitch, if the ranch of values in the switch is so wide that it takes too much memory. I think such cases are usually pretty rare, in practice. And I suspect the performance devolves to O(log(N)) in such cases - which is not bad at all for most applications.

In summary: switch statements are generally very fast. If there are indeed real-world cases where performance is a valid reason not to use a switch statement - I'd love to hear the details.

Now, as I alluded previously: this doesn't mean I recommend switch statements in general. My main objection to them is the error-prone syntax whcih requires us to explicitly provide a break. And if the possible values of the enum are changed in the future, I'd prefer to edit this in only one place (the list of values at the beginning of the enum declaration) without worrying about a separate switch statement elsewhere in the code. However - using a switch statement is not the end of the world, and Sonny's example seems fairly reasonable to me.

Typically, I define a private static class of the enum that contains a Map ,for your case, Map<Character, EnumType>, and lazily initialise it (in a static initialiser for class loader) to the appropriate values (or load them from an external resource if appropriate (the other reason why switch/case is flawed - you cannot do this)).

No disagreements on this section - this would usually be my preferred strategy as well.
[ July 05, 2005: Message edited by: Jim Yingst ]
 
Sonny Gill
Ranch Hand
Posts: 1211
Mac IntelliJ IDE
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Tony and Jim.
Very informative posts. Jim thanks for backing me on 'it making sense' he he

I read up a bit on Enum before I made the post, and was aware of the valueOf method. But having the method dictate the instance names felt a bit clunky. The private static class option you both suggest is much more intersting.

That is quite a bit of information in the two posts, I am going to read up more and experiment before implementing it.

Thanks again.
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Actually switch statements are quite capable of providing O(1) lookup - that's what the tableswitch instruction in the JVM is for.


Yes, I concede that I was over-simplifying, hoping that nobody on the forum would notice - good call anyway. Also, there is an implicit reverse mapping as you have noticed; the String representing the field name. Guess how many times the specification changed with respect to this aspect during alpha stages of release? I can recall several (in fact, that little handbook that people speak of quickly went out of date as a result).
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


(This is using the Typesafe Enum pattern in Java 2 1.4 - I can't use Tiger yet, but it probably translates well to enums, doesn't it?)
[ July 05, 2005: Message edited by: Ilja Preuss ]
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

This is using the Typesafe Enum pattern in Java 2 1.4 - I can't use Tiger yet, but it probably translates well to enums, doesn't it?


Yes it translates precisely at compile-time to the same bytecode. For example, your private constructor needs no access modifier on a 1.5 enum (it's implicitly private), and the constructor argument is passed at the declaration of the enum field (which just compiles to being passed to the constructor).

In fact, the type-safe enum is what inspired 1.5 enums.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Tony Morris:
In fact, the type-safe enum is what inspired 1.5 enums.



Ah yes. What I was concerned about is the static Map thing. Using the typesafe enum pattern, it needs to be declared before the enum constants, because otherwise it wouldn't be instanciated when the constructor gets called. Don't know how that works with Tiger enums - I guess if everything else fails you need some lazy initialization code inside the constructor...
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, that's one of the 'gotchyas', and also why I declare it as a nested class of the enum and that Map is 'lazily' populated (when that nested class is loaded implying that the enum class has already been loaded).
 
So it takes a day for light to pass through this glass? So this was yesterday's tiny ad?
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic