I need to have enum constants with byte values which can be used in a super performant sorting system. However this presents a problem when I need to get an enum from the corresponding byte value. IE fromValue().
I am wondering if the following approach of using a map of Byte values to constants is considered a bad idea when I want something that is highly optimized, or if I should just stick with static constants. What I am trying to avoid is looping through the enum values to find the correct one at runtime, which I believe would add un-needed overhead when doing millions of these operations.
public enum ReferenceTargetType {
  BINARY((byte)0x1),
  TOPIC((byte)0x2),
  MAP((byte)0x3),
  UNKNOWN((byte)0x4);
  private static Map<Byte,ReferenceTargetType> targetTypeMap = new HashMap<Byte,ReferenceTargetType>();
  static {
    for(ReferenceTargetType type : ReferenceTargetType.values()){
      targetTypeMap.put(type.getValue(), type);
    }
  }
  private byte value;
  ReferenceTargetType(byte value){
    this.value = value;
  }
  byte getValue(){
    return this.value;
  }
  static ReferenceTargetType fromValue(byte value){
    return targetTypeMap.get(value);
  }
}
Thanks
UPDATE
I created some tests to look at performance of various methods. The first method uses a hashmap, the second by looping through values, the third array offsets, and the fourth array offsets with ints instead of bytes (To see if up casting from byte to int has a performance impact), the fifth uses a switch.
Averages are over 100 runs with each run doing a 100 million fromValue() calls each. Times are in ms (I changed this from nanotime because it was blowing up on me for the larger values).
Here are the results:
- Run 1 average: 385 (HashMap lookup)
- Run 2 average: 914 (Looping through values)
- Run 3 average: 0 (Array (byte))
- Run 4 average: 0 (Array (int))
- Run 5 average: 314 (Switch)
and the code:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.HashMap;
import java.util.Map;
@RunWith(JUnit4.class)
public class EnumFromValueTest {
  static int masterRuns = 100;
  static int runs = 100000000;
  static long[] r1runs = new long[masterRuns];
  static long[] r2runs = new long[masterRuns];
  static long[] r3runs = new long[masterRuns];
  static long[] r4runs = new long[masterRuns];
  static long[] r5runs = new long[masterRuns];
  static long average(long[] values){
      int total = 0;
      for(int i = 0; i < values.length; i++)
      {
        total += values[i];
      }
      int average = total / values.length;
    return average;
  }
  public enum ReferenceTargetType1 {
    BINARY((byte)0x0),
    TOPIC((byte)0x1),
    MAP((byte)0x2),
    UNKNOWN((byte)0x3);
    private static
    Map<Byte,ReferenceTargetType1>
        targetTypeMap = new HashMap<Byte, ReferenceTargetType1>();
    static {
      for(ReferenceTargetType1 type : ReferenceTargetType1.values()){
        targetTypeMap.put(type.getValue(), type);
      }
    }
    private byte value;
    ReferenceTargetType1(byte value){
      this.value = value;
    }
    byte getValue(){
      return this.value;
    }
    static ReferenceTargetType1 fromValue(byte value){
      return targetTypeMap.get(value);
    }
  }
  public enum ReferenceTargetType2 {
    BINARY((byte)0x0),
    TOPIC((byte)0x1),
    MAP((byte)0x2),
    UNKNOWN((byte)0x3);
    private byte value;
    ReferenceTargetType2(byte value){
      this.value = value;
    }
    byte getValue(){
      return this.value;
    }
    static ReferenceTargetType2 fromValue(byte value){
      for(ReferenceTargetType2 type : ReferenceTargetType2.values()){
        if(type.getValue() == value)
          return type;
      }
      return null;
    }
  }
  public enum ReferenceTargetType3 {
    BINARY((byte)0x0),
    TOPIC((byte)0x1),
    MAP((byte)0x2),
    UNKNOWN((byte)0x3);
    private byte value;
    private static ReferenceTargetType3[] values = new ReferenceTargetType3[ReferenceTargetType3.values().length];
    static {
      int i = 0;
      for(ReferenceTargetType3 type : ReferenceTargetType3.values()){
       values[i]= type;
        i++;
      }
    }
    ReferenceTargetType3(byte value){
      this.value = value;
    }
    byte getValue(){
      return this.value;
    }
    static ReferenceTargetType3 fromValue(byte value){
      return values[value];
    }
  }
  public enum ReferenceTargetType4 {
    BINARY(0),
    TOPIC(1),
    MAP(2),
    UNKNOWN(3);
    private int value;
    private static ReferenceTargetType4[] values = new ReferenceTargetType4[ReferenceTargetType4.values().length];
    static {
        int i = 0;
        for(ReferenceTargetType4 type : ReferenceTargetType4.values()){
          values[i]= type;
          i++;
        }
    }
    ReferenceTargetType4(int value){
      this.value = value;
    }
    int getValue(){
      return this.value;
    }
    static ReferenceTargetType4 fromValue(int value){
      return values[value];
    }
  }
  public enum ReferenceTargetType5 {
    BINARY((byte)0x0),
    TOPIC((byte)0x1),
    MAP((byte)0x2),
    UNKNOWN((byte)0x3);
    private byte value;
    ReferenceTargetType5(byte value){
      this.value = value;
    }
    byte getValue(){
      return this.value;
    }
    static ReferenceTargetType5 fromValue(byte value) {
      switch (value) {
        case 0x0: return BINARY;
        case 0x1: return TOPIC;
        case 0x2: return BINARY;
        case 0x3: return UNKNOWN;
        default:  return UNKNOWN;
      }
    }
  }
  @Test
  public void doPerformanceTest(){
    for(int i = 0; i < masterRuns;i++){
      doRuns(i);
    }
    System.out.println("Run 1 average: " + average(r1runs));
    System.out.println("Run 2 average: " + average(r2runs));
    System.out.println("Run 3 average: " + average(r3runs));
    System.out.println("Run 4 average: " + average(r4runs));
    System.out.println("Run 5 average: " + average(r5runs));
  }
  public void doRuns(int runnum){
    ReferenceTargetType1 type1 = ReferenceTargetType1.UNKNOWN;
    ReferenceTargetType2 type2 = ReferenceTargetType2.UNKNOWN;
    ReferenceTargetType3 type3 = ReferenceTargetType3.UNKNOWN;
    ReferenceTargetType4 type4 = ReferenceTargetType4.UNKNOWN;
    ReferenceTargetType5 type5 = ReferenceTargetType5.UNKNOWN;
    long startTime1 = System.currentTimeMillis();
    for(int i = 0; i < runs;i++){
      ReferenceTargetType1.fromValue(type1.getValue());
    }
    r1runs[runnum] = (System.currentTimeMillis() - startTime1);
    long startTime2 = System.currentTimeMillis();
    for(int i = 0; i < runs;i++){
      ReferenceTargetType2.fromValue(type2.getValue());
    }
    r2runs[runnum] = (System.currentTimeMillis() - startTime2);
    long startTime3 = System.currentTimeMillis();
    for(int i = 0; i < runs;i++){
      ReferenceTargetType3.fromValue(type3.getValue());
    }
    r3runs[runnum] = (System.currentTimeMillis() - startTime3);
    long startTime4 = System.currentTimeMillis();
    for(int i = 0; i < runs;i++){
      ReferenceTargetType4.fromValue(type4.getValue());
    }
    r4runs[runnum] = (System.currentTimeMillis() - startTime4);
    long startTime5 = System.currentTimeMillis();
    for(int i = 0; i < runs;i++){
      ReferenceTargetType5.fromValue(type5.getValue());
    }
    r5runs[runnum] = (System.currentTimeMillis() - startTime5);
  }
}
 
     
     
     
    