1

With an enum like this one where each key has several values

ABBR1("long text 1", "another description 1", "yet another one 1"), 
ABBR2("long text 2", "another description 2", "yet another one 2"), 
//and so on...

how can I reverse lookup an abbreviation (constant) by calling a method like getAbbreviation(descriptionText)?

I'm basically looking for an implementation as described here, I think, but with the difference that each ENUM key (constant) has several values coming with it, and I want it to work with getAbbreviation("long text 1") as well as with getAbbreviation("yet another one 2")...

Is there an easy way to loop over each ENUM's (i.e. ABBRn's) value fields, to populate a giant map, or is there maybe even a better solution?

Community
  • 1
  • 1
Christian
  • 6,070
  • 11
  • 53
  • 103

3 Answers3

2

Each enum has a method values() so You can do like that:

for(YourEnum type : values()){
        if(/*is Equal to Your descriptionText*/){
             return type;
        }
    }
    throw new IllegalArgumentException("No such BailiffPaymentStatus:"+dbRepresentation);
maslan
  • 2,078
  • 16
  • 34
  • Do you know what Java class that `values()` method is defined? Is it the one in `java.lang Enum`? If so, that class must describe an ENUM constant and its values - which would raise the question where enum "classes" are defined...? – Christian Oct 13 '14 at 11:02
  • 1
    Yes it is defined in Enum class itself. If You would decompile Your enum, You would notice that is is more-or-less a quite simple class http://theopentutorials.com/tutorials/java/enum/enum-converted-to-class/ – maslan Oct 13 '14 at 11:21
  • 1
    @Christian There is no `values()` method in [`java.lang.Enum`](http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html), it's a synthetic method of the actual enum type. – kapex Oct 13 '14 at 11:28
  • @kapep: I assume the type itself is implemented in Java? If so, is there a way to look at the source code? Just being curious... – Christian Oct 13 '14 at 11:30
  • @Christian It's compiler generated, so I don't think you can find a real source file. The java specification should contain some information about it though, and you can look at the code using `javap` - or just look at the code in the link maslan posted, it's a quite simple method that just returns an array of enum constants. – kapex Oct 13 '14 at 11:35
  • @Christian the real real source file does not exist, but by decompiling it, You can see the logic behind it, it's pretty simple. – maslan Oct 13 '14 at 11:39
2

This relies on the fact that the enum member constructors are run before the static initializer. The initializer then caches the members and their long forms.

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public enum Abbreviation {
    ABBR1("long text 1", "another description 1", "yet another one 1"), 
    ABBR2("long text 2", "another description 2", "yet another one 2"); 

    private static final Map<String, Abbreviation> ABBREVIATIONS = new HashMap<>();

    private String[] longForms;
    private Abbreviation(String... longForms) {
        this.longForms = longForms;
    }

    public String toString () {
        return Arrays.toString(longForms);
    }

    static {
        for(Abbreviation abbr : values()) {
            for(String longForm : abbr.longForms) {
                ABBREVIATIONS.put(longForm, abbr);
            }

        }
    }

    public static Abbreviation of(String longForm) {
        Abbreviation abbreviation = ABBREVIATIONS.get(longForm);
        if(abbreviation == null) throw new IllegalArgumentException(longForm + " cannot be abbreviated");
        return abbreviation;
    }



    public static void main(String[] args) {
        Abbreviation a =  Abbreviation.of("yet another one 2");
        System.out.println(a == Abbreviation.ABBR2); //true
    }
}
c.P.u1
  • 16,664
  • 6
  • 46
  • 41
  • What would I have to change if I needed a reference for each of the argument's constructors, e.g. `private Abbreviation(String longText, String desc1, String desc2) { this.longText = longText; //etc`? I'm guessing `for(String longForm : abbr.longForms)` won't work for that? – Christian Oct 13 '14 at 12:39
  • 1
    I thought each abbreviation could have a variadic number of long forms. Since you have a fixed number of arguments, you'll need to construct an array with all 3 arguments for each enum member. `private Abbreviation(String longText, String desc1, String desc2) { this.longForms = new String[] {longText, desc1, desc2}; }` – c.P.u1 Oct 13 '14 at 12:46
  • So, there is no built-in way to loop over an (i.e. one single) ENUM **constant**'s values? – Christian Oct 13 '14 at 12:47
1

I think the solution from: c.P.u1 is on the right track. However there is a more direct way to populate the HashMap as you go using the solution from this question.

  • How to facilitate Netbeans Designer to load JPanel-s that use an enum reverse-lookup using hashmap?

        private static final Map<String, Abbreviation> abbreviationMap;
    
        private Abbreviation(String... longForms) {
            this.longForms = longForms;   //  optional
            mapAbbreviations( this, longForms )
        }
    
        private static void mapAbbreviations( final Status state, String... longForms ){
            if( null ==  abbreviationMap  ){
                abbreviationMap  = new HashMap( 20 );
            }
            for( String abbrev : longForms ){
                abbreviationMap.put( abbrev,  state );
            }
        }
    

Also, you don't really need the private longForms string array for the toString() function, since all the values are saved with the Map anyway.

Community
  • 1
  • 1
will
  • 4,799
  • 8
  • 54
  • 90