1

With the use of below code, I am finding out which datacenter I am in and it is working fine..

public enum DatacenterEnum {

    DEV, DC1, DC2, DC3;

    private static DatacenterEnum compareLocation() {
        String ourhost = getHostName();

        for (DatacenterEnum dc : values()) {
            String namepart = "." + dc.name().toLowerCase() + ".";
            if (ourhost.indexOf(namepart) >= 0) {
            return dc;
            }
        }
        return null;// I don't want to do this now.
    }
}

But it might be possible that it is not able to find any datacenter, so currently I am returning null.

Is there any direct way or a single line command by which I can return randomly either DC1 or DC2 or DC3 in the ENUM instead of returning null?

I know one way is to make a list of string and then randomnly select any integer between 0 to 2 inclusive and then find the string. But it is too much code, actually it's not but just trying to see is there any other way we can do this?

Any simple and direct way which I can use in the ENUM directly?

AKIWEB
  • 19,008
  • 67
  • 180
  • 294
  • AFAIK, there isn't such a way. But in case I am wrong, looking forward to an answer to this. – Chthonic Project Jan 16 '14 at 23:19
  • 2
    Have you looked at what `values()` returns? And thought about how to select an appropriate random element based on that? You don't need to create a list of strings... – Jon Skeet Jan 16 '14 at 23:20
  • 1
    possible duplicate of [Java: Pick a random value from an enum?](http://stackoverflow.com/questions/1972392/java-pick-a-random-value-from-an-enum) – Behe Jan 16 '14 at 23:21
  • In my case, I have DEV as well but I don't need to choose DEV with randomness only DC1, DC2, DC3. – AKIWEB Jan 16 '14 at 23:23

3 Answers3

3

Here's the one line:

return DataCenterEnum.values()[new Random().nextInt(3) + 1)];

For those who require tighter control on their code, here's a safer version, which does not depend on the order of the enum instances:

return new DataCenterEnum[]{DC1, DC2, DC3}[new Random().nextInt(3)];
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    Downvoted because this depends on the elements ordering to ignore `DEV`. – everton Jan 17 '14 at 00:04
  • @EvertonAgner so, you think this answer is not useful? You should get over yourself. The line of code and the enum onstances on which it depends are **in the same class**. That makes it totally safe and "best practice"; any code ugliness is self contained and affects nothing but the class itself - an implementation detail. Anyone changing the enum order is obliged to fix the random chooser, which would be trivial btw - it's super trivial now because they're in order, but any combo could be dealt with using simple math to work around gaps in sequences, which will in all likelihood never happen – Bohemian Jan 17 '14 at 00:23
  • I've just explained my downvote. That's common courtesy. – everton Jan 17 '14 at 00:25
  • 1
    @EvertonAgner yes, that is. Well just for you I've added a "safe" version. – Bohemian Jan 17 '14 at 00:36
  • 1
    @EvertonAgner hmmmm... I must do some more research into this "playing nice" thing I've heard so much about :) – Bohemian Jan 17 '14 at 01:38
1

Here is a generic solution that will work for any enumeration.

Convenience method for single exclusion:

public static <E extends Enum<E>> E getRandom(Class<E> aEnum, E exclude) {
    return getRandom(aEnum, Collections.singletonList(exclude));
}

Generic method that works with one or more exclusions:

public static <E extends Enum<E>> E getRandom(Class<E> aEnum, List<E> exclude){
    //Convert set of enums into a list
    List<E> enums = new ArrayList<E>(EnumSet.allOf(aEnum));

    //Remove items from the list that you want to exclude
    enums.removeAll(exclude);

    int size = enums.size();
    if(size != 0){
        //Get random enum
        int randomIndex = new Random().nextInt(size);
        return enums.get(randomIndex);
    } else {
        throw new IllegalArgumentException("Empty Enumeration after excludes");
    }
}

For your example you could call

EnumUtil.getRandom(DatacenterEnum.class, DatacenterEnum.DEV);
JustinKSU
  • 4,875
  • 2
  • 29
  • 51
  • You could also use a varargs instead of list getRandom(Class aEnum, E...exclude), just change to removeAll line to enums.removeAll(Arrays.asList(exclude)); – JustinKSU Jan 17 '14 at 19:39
0

You could use the values() method, which returns an array. Then just use Math.random() to return a random instance.

Here is an example:

public static void main (String[] args) {
    String[] arr = {"DEV","DC1","DC2","DC3"}; //returned by Enum.values(), you get the idea
    String randElement = arr[(int) ((Math.random() * 3) +1)]; 
    System.out.println(randElement);
}

Basically it boils down to generating a random number between 1 and n :)

kmera
  • 1,725
  • 10
  • 22
  • In my case, I have DEV as well but I don't need to choose DEV with randomness only DC1, DC2, DC3. Can you provide an example on this? – AKIWEB Jan 16 '14 at 23:25
  • what about creating a random value between 1 and 3, not 0 and 3. – kmera Jan 16 '14 at 23:26
  • @AKIWEB - see my solution above using a constructor and random. I think that's the cleanest we can do with enums! – avijendr Jan 16 '14 at 23:49