2

I have an enum:

 public enum ScopeItems {
   BASIC_INFO, POLICY_INFO, USER_INFO
 };

And I have a number of Auth objects which might hold any combination of these scopes.

What I want to do is assign an integer value depending on which of these scope items the Auth object holds.

So for example assume:

BASIC_INFO = 1; POLICY_INFO = 2; USER_INFO = 4;

If I have an integer value of 5 then I'd want to return an array with:

BASIC_INFO, USER_INFO

I also want it to work in reverse, so if I pass in an array of POLICY_INFO, USER_INFO I'd get 6 back.

I've got this working, but my solution seemed a bit too complicated for what it is. I'm sure there are better ways of going about it I'm not thinking of.

user7862512
  • 273
  • 1
  • 9
  • 3
    What did you try? – Stefan Jan 29 '18 at 15:19
  • The appropriate thing to use is [EnumSet](https://docs.oracle.com/javase/9/docs/api/java/util/EnumSet.html). – Klitos Kyriacou Jan 29 '18 at 15:24
  • You should maybe read the item in Effective Java about why you shouldn't use bitmasks (basically: they're not type safe, they're a bit confusing etc). An `EnumSet` is preferable. – Andy Turner Jan 29 '18 at 15:27
  • @AndyTurner Well then alternatively how would I represent this value in a db efficiently? – user7862512 Jan 29 '18 at 15:29
  • 2
    Еnum is an object. Add field `int value` to enum class, and create a constructor : `ScopeItems(int I){ this.value = I;}` -> `BASIC_INFO(1), POLICY_INFO(2), USER_INFO(4)` ... And you can add a method like `public int getValue(){...}`. – kozmo Jan 29 '18 at 15:30
  • 1
    https://stackoverflow.com/questions/2199399/storing-enumset-in-a-database – Klitos Kyriacou Jan 29 '18 at 15:41
  • @Stefan Looping over the ENum which assumes the order is kept the same. Then comparing items in the array and adding an int value where items existed. It was quite messy and I don't like the fact it was assuming the ENum would always be in the same order. I would post the code, but I've been playing around with other ways to do it and I've lost that code. – user7862512 Jan 29 '18 at 15:42
  • 1
    Possible duplicate of [Storing EnumSet in a database?](https://stackoverflow.com/questions/2199399/storing-enumset-in-a-database) – Ole V.V. Jan 29 '18 at 15:43

1 Answers1

3

The following enum should accomplish what you want:

public enum ScopeItems {

    BASIC_INFO(1), POLICY_INFO(2), USER_INFO(4);

    private final int score;
    public int getScore() {
        return score;
    }
    private ScopeItems(int score) {
        this.score = score;
    }

    public static Set<ScopeItems> getScopeByScore(int score) {
        return Stream.of(values()).filter(i -> (i.getScore() | score) == score).collect(Collectors.toSet());
    }

    public static int getScoreByItems(Set<ScopeItems> items) {
        return items.stream().mapToInt(i -> i.getScore()).sum();
    }

};

Efficiency improvement in getScopeByStore() suggested by Klitos:

.collect(Collectors.toSet())   // Inefficient
.collect(Collectors.toCollection(() -> EnumSet.noneOf(ScopeItems.class)) // Better!

And how to use it:

ScopeItems.getScopeByScore(5);   // Returns the Set

ScopeItems.getScoreByItems(EnumSet.of(ScopeItems.BASIC_INFO, ScopeItems.POLICY_INFO))  // Returns the score

There is no current validation; the enum would improve if the methods validated the input.

Ian Mc
  • 5,656
  • 4
  • 18
  • 25
  • 1
    It would be nice if `getScopeByScore` returned an `EnumSet`, which is more efficient than the type of `Set` that `.collect(Collectors.toSet()))` gives you. You can achieve that with `.collect(Collectors.toCollection(() -> EnumSet.noneOf(ScopeItems.class)))`. – Klitos Kyriacou Jan 29 '18 at 16:21
  • Thanks, this works perfectly and was much cleaner than what I was doing! =) – user7862512 Jan 29 '18 at 18:40