2

What if I'll use switch in getByIntValue()? Is it really neccessary to use a SparseArray?

public enum Gender {
    Unknown(0),
    Male(1),
    Female(2);

    private static final SparseArray<Gender> lookupTable = new SparseArray<Gender>();
    static {
        for (final Gender gender : EnumSet.allOf(Gender.class)) {
            lookupTable.put(gender.intValue, gender);
        }
    }

    private final int intValue;

    public static Gender getByIntValue(int val) {
        return lookupTable.get(val);
    }

    private Gender(int intValue) {
        this.intValue = intValue;
    }

    public int getIntValue() {
        return intValue;
    }
}
Eugene
  • 59,186
  • 91
  • 226
  • 333
  • Why don't you switch on the enum `Gender` itself? – Srinivas Jan 25 '13 at 09:52
  • switch only works with constant values. final field of instance does not count. – notXX Jan 25 '13 at 09:53
  • No that isn't necessary. Your enum is not sparse. Not to mention it currently only has three members. This approach would be used for "switching" on strings or similar. e.g Lookup string in an arrayand use it's position in the array in the switch or as a look up for teh action in the event of a match. – Tony Hopkinson Jan 25 '13 at 09:57

3 Answers3

2

If you have posted realistic int values, then you don't need to set them explicitly on each enum member, and don't need switch. Just use

Gender.values()[intValue]
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Do you feel that usage of an `intValue` which has one-to-one mapping is required? I think that the value is coming from UI drop down or similar which can be modified to return the Enum value itself. – Srinivas Jan 25 '13 at 09:58
  • 2
    That concern is out of the scope of this question. – Marko Topolnik Jan 25 '13 at 10:03
2

Since your int values go from 0 to 2, without hole, you could indeed simply use an array. A switch would also be fine, although it would probably be slightly slower than an array lookup. But unless you call the method billions of times, it won't make any noticeable difference. Use what you find the clearest and easiest to understand and maintain.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Such an array is already provided in all Java enums, OP doesn't need to implement it himself. – Marko Topolnik Jan 25 '13 at 09:56
  • Agreed, except if he wants to avoid a new array creation at each method invocation (which I would try to avoid myself, although it wouldn't matter much). – JB Nizet Jan 25 '13 at 09:58
  • Hm, never thought about this, but you are obviously right. I was under the impression that `values()` returned a constant array, but that of course is impossible. – Marko Topolnik Jan 25 '13 at 09:59
  • 1
    What what what? I missed something here. Do you have a link to the implementation of `values`? Found it [here](http://stackoverflow.com/questions/1163076/how-is-values-implemented-for-java-6-enums). I had never thought of that either... – assylias Jan 25 '13 at 10:05
  • If you think about it, returning a constant array is indeed impossible, since arrays are mutable. You don't want anyone to be able to modify the values of an enum by setting all the array elements to something else, or by sorting the array, or whatever. So a new array is created each time `values()` is invoked. I think I've read that Sun had considered returning an unmodifiable list instead, but that benchmarks and studies revealed that creating a new array each time was faster and easier. – JB Nizet Jan 25 '13 at 10:18
  • Yes, I'm sure array's `clone` method can be optimized to assembler levels, and `asList` still involves allocation. – Marko Topolnik Jan 25 '13 at 12:07
0

List.copyOf( EnumSet.allOf( Gender.class ) )

Caveat: This exercise in optimization seems silly for all but the most extreme scenario, as mentioned by JB Nizet. For real work, I would probably recommend the solution seen in the Answer by Marko Topolnik. But, for fun, I swung a bat at this ball.

Seems the goal is to render a static unmodifiable collection with very fast access by the given numbers 0, 1, 2.

As of Java 10, we have these new implemented (“default”) methods on the List interface: List.of & List.copyOf. These produce an unmodifiable collection. Though the backing implementation is undocumented and subject to change, I will assume it is something akin to an array with similar performance. Performance might even be faster than a conventional array, if the backing implementation detected the presence of an EnumSet and used some kind of bit vector.

I populate the List by passing an EnumSet to List.copyOf( Collection ).

So, this:

private static final SparseArray<Gender> lookupTable = new SparseArray<Gender>();
static {
    for (final Gender gender : EnumSet.allOf(Gender.class)) {
        lookupTable.put(gender.intValue, gender);
    }
}

…becomes this:

private static final List < Gender > lookupTable = List.copyOf( EnumSet.allOf( Gender.class ) );

Entire class, with main for demo.

package com.basilbourque.example;

import java.util.EnumSet;
import java.util.List;

public enum Gender {
    UNKNOWN( 0 ),
    MALE( 1 ),
    FEMALE( 2 );

    private static final List < Gender > lookupTable = List.copyOf( EnumSet.allOf( Gender.class ) );

    private final int intValue;

    public static Gender getByIntValue ( int val ) {
        return lookupTable.get( val );
    }

    public int getIntValue () {
        return intValue;
    }

    // Constructor
    private Gender ( int intValue ) {
        this.intValue = intValue;
    }

    public static void main ( String[] args ) {
        // Testing.
        System.out.println( Gender.UNKNOWN.intValue );
        System.out.println( Gender.getByIntValue( 0 ) );
        System.out.println( "----" );
        System.out.println( Gender.MALE.intValue );
        System.out.println( Gender.getByIntValue( 1 ) );
        System.out.println( "----" );
        System.out.println( Gender.FEMALE.intValue );
        System.out.println( Gender.getByIntValue( 2 ) );
    }

}

When run.

0

UNKNOWN


1

MALE


2

FEMALE


By the way, as the biological default, FEMALE should come before MALE.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154