views:

62

answers:

5

I have a list of constants and want to check if a value passed to a method equals one of the constants. I know Enums which would be fine, but I need an int value here for performance reasons. Enum values can have a value, but I'm afraid the getting the int value is slower than using an int directly.

public static final int 
  a = Integer.parseInt("1"), // parseInt is necessary in my application
  b = Integer.parseInt("2"), 
  c = Integer.parseInt("3");

public void doIt(int param) {
  checkIfDefined(param);
  ...
}

The question is about checkIfDefined. I could use if:

if(param == a)
  return;
if(param == b)
  return;
if(param == c)
  return
throw new IllegalArgumentException("not defined");

Or I could use a Arrays.binarySearch(int[] a, int key), or ... any better idea?

Maybe enums would be better not only in elegance but also in speed, because I don't need the runtime checks.

Solution

Since whether enum nor switch worked in my special case with parseInt, I use plain old int constants together with Arrays.binarySearch now.

A: 

How about a switch statement. You can throw exception in the default case.

Sunny
deamon
He passes int to checkIfDefined(int). And the switch statement will be there.
Sunny
Believe me - it doesn't work (I believe the compiler ;-) ).
deamon
Ups, you are right, I did not read the request fully. In any case, the problem is, that a, b and c are not constant, not because of the parseInt. But an enum solution will again require a "constant", so I dunno, may only a list solution will do.
Sunny
+1  A: 

I am reasonably sure that getting an int property value of an enum is about as fast as getting the value of an int constant. (But if in doubt, why not make a prototype and measure the performance of both solutions?) Using enums makes your code so much more readable, it is always worth that little extra effort.

For fast lookup, if you only have unsigned integer values, you could store the enum values in an ArrayList, indexed by their respective int value.

Péter Török
+1  A: 

Do you prefer to use enums:

public enum Letters {
    A("1"), B("2"), C("3");

    private final String value;

    private Letters(String value) {
        this.value = value;
    }

    public Letters getByValue(String value) {
        for (Letters letter : values()) {
            if (letter.value.equals(value)) return letter;
        }
        throw new IllegalArgumentException("Letter #" + value + " doesn't exist");
    }

    public int toInt() {
        return Integer.parseInt(value);
    }
}
Boris Pavlović
enums would be better, but I have the same problem with the compiler telling me `constant expression required`.
deamon
+1  A: 

If your list of constants is long, load them into a HashSet. That will give you the fastest lookup time: all lookups into hash maps are O(1) time (and with low constant cost, too, aside from the autoboxing of the integer).

If your list of constants is short and invariant, use a switch statement and let the compiler essentially build a HashSet for you (with no autoboxing).

If it's somewhere in between, throw them into an array, sort it, and use Arrays.binarySearch. You can do about 5-10 comparisons in the time it takes to box one integer, so I would switch over to HashSet once the number gets into the hundreds.

If it's a very short, and you know which number is most likely to come up, code it by hand in if statements, checking the most common ones first.

Rex Kerr
A: 

I guess the array solution you posted is fasted as long as the number of params stays small. If it gets larger than 128 and you need this frequently, then I would go with a HashSet:

Set<Integer> params = new HashSet<Integer>();
params.add(Integer.valueOf("1"));
params.add(Integer.valueOf("2"));
params.add(Integer.valueOf("3"));

public boolean checkIfDefined(int param){
    return params.contains(param);
}

The auto-boxing is certainly slow, but the hash look-up O(1) and not O(log n) as the binary search.

2.) The fasted solution if memory is not much of a concern or the parameters are not going up to a high value is the use of boolean[] using the params as an index:

boolean[] params = new boolean[MAX_PARAMS+1];
params[Integer.parseInt("1")] = true;
params[Integer.parseInt("2")] = true;
params[Integer.parseInt("3")] = true;

public boolean checkIfDefined(int param){
    if (param < 0 || params.length <= param)
        return false;
    return params[param];
}
Christopher Oezbek