4

I read here a nice example about using ImmutableSet from Guava. The example is reported here for the sake of completeness:

public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
  "red",
  "orange",
  "yellow",
  "green",
  "blue",
  "purple");

class Foo {
  Set<Bar> bars;
  Foo(Set<Bar> bars) {
    this.bars = ImmutableSet.copyOf(bars); // defensive copy!
  }
}

The question is, can I obtain the same result by using a Java enum?

PS: This question added into my mind more chaos!

Community
  • 1
  • 1
mat_boy
  • 12,998
  • 22
  • 72
  • 116
  • do you ask the difference between java enum and guava ImutablSet or do you want to get a guava imutableSet from an existing java enum?? – Kent Apr 11 '13 at 15:11
  • @Kent I was just asking if there is any specific reason in that example to not use a Java enum. – mat_boy Apr 11 '13 at 15:13
  • because they are different things... the article is for `ImmutableSet` how come making an enum example there? ... so you were asking the difference between the two things? – Kent Apr 11 '13 at 15:16
  • About PS: the question you've found is not about simple `Sets.immutableEnumSet(EnumSet.allOf(Color.class))` which works for 99% of times, but rather special use case when memory footprint was more important for OP than nice level of abstraction - i.e. he was ready to use arrays which aren't nice to use. – Grzegorz Rożniecki Apr 11 '13 at 15:20
  • btw, `this.bars = ImmutableSet.copyOf(bars);` does not actually create a copy. It doesn't make sense to create defensive copies of immutable collections, so ImmutableSet.copyOf(immutableSet) returns the original ImmutableSet (see here: http://docs.guava-libraries.googlecode.com/git/javadoc/src-html/com/google/common/collect/ImmutableSet.html#line.359 ) – Sean Patrick Floyd Apr 12 '13 at 10:04

3 Answers3

10

Can I obtain the same result by using a Java enum?

Yes, you can. Did you try it?

FYI There's also specialized version of ImmutableSet which holds enum's constants - Sets.immutableEnumSet (internally it uses EnumSet).

Some examples (paraphrasing Wiki examples):

public class Test {

  enum Color {
    RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE;
  }

  static class Baz {
    ImmutableSet<Color> colors;

    Baz(Set<Color> colors) {
      this.colors = Sets.immutableEnumSet(colors); // preserves enum constants 
                                                   // order, not insertion order!
    }
  }

  public static void main(String[] args) {
    ImmutableSet<Color> colorsInInsertionOrder = ImmutableSet.of(
        Color.GREEN, Color.YELLOW, Color.RED);
    System.out.println(colorsInInsertionOrder); // [GREEN, YELLOW, RED]
    Baz baz = new Baz(colorsInInsertionOrder);
    System.out.println(baz.colors); // [RED, YELLOW, GREEN]
  }
}

EDIT (after OP's comment):

Do you want all enum constants in ImmutableSet? Just do:

Sets.immutableEnumSet(EnumSet.allOf(Color.class));
Pang
  • 9,564
  • 146
  • 81
  • 122
Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
  • Hi! Is there any reason to prefer java enum to ImmutableSet or ImmutableEnumSet? – mat_boy Apr 11 '13 at 15:14
  • Same as using `HashSet` / `LinkedHashSet` vs [`EnumSet`](http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html) - EnumSet is faster when using enum constants as elements than eny other set (From JDK's docs: *Implementation note: All basic operations execute in constant time. They are likely (though not guaranteed) to be much faster than their HashSet counterparts. Even bulk operations execute in constant time if their argument is also an enum set.* ) and ImmutableEnumSet is using EnumSet internally to store elements. – Grzegorz Rożniecki Apr 11 '13 at 15:17
  • Thank you! Thus, I will prefer enums to an final static `ImmutableSet` of `String` objects. Moreover, I will construct sets by using an `EnumSet`. – mat_boy Apr 11 '13 at 15:34
3

No, not quite. Compare

public enum Color {
    RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE;
}

Set<Color> colors = EnumSet.allOf(Color.class);

with

Set<String> colors = ImmutableSet.of(
  "red", "orange", "yellow", "green", "blue", "purple"
);

Since Java is statically typed, you will have a Set<Color> in the first example, and a Set<String> in the latter example.

Edit 1

Another difference is that you can create ImmutableSet of arbitrary size in runtime (provided that no single element equals() any of the other elements). In contrast, an EnumSet can also be created during runtime, but it can never contain more elements than the number of enum values.

Edit 2

An ImmutableSet may contain elements of different classes, as long as they implement the same interface. An EnumSet can only contain the enum type.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • I can also do `Set colors= ImmutableSet.copyOf(Color.values())`. What does change with respect to the use of `EnumSet`? – mat_boy Apr 11 '13 at 15:26
  • Thank you for the details +1. It seems to me that it is preferable to use enums instead of String objects! – mat_boy Apr 11 '13 at 15:39
  • 1
    `ImmutableSet.copyOf(Color.values())` does full linear-time copy of all elements while `Sets.immutableEnumSet(EnumSet.allOf(Color.class))` does EnumSet.clone internally which should be faster. – Grzegorz Rożniecki Apr 11 '13 at 15:42
  • @Xaerxess "should"? So, YOU are not sure about something :) I'm verydisappointed lol – mat_boy Apr 11 '13 at 18:57
0

If you don't have all these fancy utility libraries as dependecies, you can use standard way:

enum Furniture{SOFA, CHAIR, TABLE};
Set<Furniture> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(Furniture.values())));

BTW: isn't it the most efficient way? I saw a lot of code inside those library's methods, probably it is overkill? Anyway, it depends on context. My approach is a bit verbose and don't do some optimizations like cacheing and so on, but it is independent and exactly what OP is asking for.

WeGa
  • 801
  • 4
  • 10
  • 24