1

Assume we have two or more enums and one Set containing all enum elements, like in:

import java.util.Map;
import java.util.Set;
import java.util.HashSet;

public class Foo {

    interface FooEnum {}

    enum FooEnum1 implements FooEnum {
        K1,
        K2
    }

    enum FooEnum2 implements FooEnum {
        K3,
        K4
    }


    static public Set<FooEnum> all = new HashSet<FooEnum>();

    public static void main(String [] args) {
      Foo it = new Foo();

      it.all.add( FooEnum1.K1 );
      it.all.add( FooEnum1.K2 );
      it.all.add( FooEnum2.K3 );
      it.all.add( FooEnum2.K4 );

      for( FooEnum k : it.all ) {
        System.out.println( k.toString() );
      }
    }
}

it is possible to fill the all set without one "add" for each set member NOR A LOOP for each enum (outside the enum itself) ? That is, fill it inside an enum constructor or static code?

** Addendum **

In other words, the objective is that addition of one enum element or addition of a new enum that implements FooEnum doesn't needs new lines of code to fill the set (that a programmer could forget causing an error).

Better, if initialization of "add" is done in constructors or static code.

** Addendum 2 **

Following code is similar to what is expected, but doesn't produces the expect result:

import java.util.Map;
import java.util.Set;
import java.util.HashSet;

public class Foo {

    interface FooEnum {
    }

    static public Set<FooEnum> all = new HashSet<FooEnum>();

    enum FooEnum1 implements FooEnum {
        K1,
        K2;

    FooEnum1() {
        all.add(this);
    }
    }

    enum FooEnum2 implements FooEnum {
        K3,
        K4;

    FooEnum2() {
        all.add(this);
    }
    }



    public static void main(String [] args) {
      Foo it = new Foo();

      for( FooEnum k : it.all ) {
        System.out.println( k.toString() );
      }
    }
}

following one fails also:

import java.util.Map;
import java.util.Set;
import java.util.HashSet;

public class Foo {

    interface FooEnum {
    }

    enum FooEnum1 implements FooEnum {
        K1,
        K2;

      static {
        for( FooEnum1 e : FooEnum1.values() ) {
            all.add(e);
        }
      }
    }

    enum FooEnum2 implements FooEnum {
        K3,
        K4;

      static {
        for( FooEnum2 e : FooEnum2.values() ) {
            all.add(e);
        }
      }
    }


    static public Set<FooEnum> all = new HashSet<FooEnum>();

    public static void main(String [] args) {
      Foo it = new Foo();

      for( FooEnum k : Foo.all ) {
        System.out.println( k.toString() );
      }
    }
}
pasaba por aqui
  • 3,446
  • 16
  • 40

3 Answers3

6

You may want to use Set#addAll(Collection). It will automatically add all the Enum values to the HashSet

it.all.addAll(Arrays.asList(FooEnum1.values()));
it.all.addAll(Arrays.asList(FooEnum2.values()));

If you're using , here is a oneliner.

  it.all.addAll(Stream.of(FooEnum1.values(), FooEnum2.values())
                      .flatMap(x -> Arrays.stream(x)).collect(Collectors.toSet()));

You may not gain in readability but it's a oneliner.

Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
6

Using EnumSet#allOf seems like a relatively easy way to solve this:

it.all.addAll(EnumSet.allOf(FooEnum1.class));
it.all.addAll(EnumSet.allOf(FooEnum2.class));
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • Thanks for the answer. However, looking for a solution that doesn't needs one line for each enum . Question clarified. – pasaba por aqui May 27 '16 at 18:35
  • @Tom: Sorry if my explanations are not enough. The answer contains two statements, one for "FooEnum1", another one for "FooEnum2". If a programmer adds a new "FooEnum3" but forgets to add a new line like the ones in the answer, we have an error. I want to skeep this possibility. – pasaba por aqui May 27 '16 at 18:38
  • @pasabaporaqui The problem is, that this code doesn't know which enums you like to add, since it doesn't know which enums exist. You might want to find each enum which implements `FooEnum` (like [here](http://stackoverflow.com/questions/347248/how-can-i-get-a-list-of-all-the-implementations-of-an-interface-programmatically)), but the resulting code, might be unclear/hard to understand. – Tom May 27 '16 at 18:41
  • @Tom: A new addendum to the original question has been written, hope this clarify. – pasaba por aqui May 27 '16 at 18:48
1

You can do it in one line too:

Stream.<FooEnum[]>of(FooEnum1.values(), FooEnum2.values())
    .map(Arrays::asList).forEach(it.all::addAll);

For a more exotic approach:

static public Set<FooEnum> all = new HashSet<FooEnum>();

interface FooEnum {
    default void register() { // you can name this method however you want
        all.add(this);
    }
}

enum FooEnum1 implements FooEnum {
    K1,
    K2;

    FooEnum1() {
        register();
    }
}

enum FooEnum2 implements FooEnum {
    K3,
    K4;

    FooEnum2() {
        register();
    }
}

This approach has the advantage of decoupling the set from the enum class - only the interface knows about the set. You do have to code a call to register() in the enum's constructor, but that's all. Every instance will "automatically" be added to the set.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Thanks for the answer, however, the statement contains "FooEnum1"and "FooEnum2". Looking for a solution without. See question clarification. – pasaba por aqui May 27 '16 at 18:49
  • 2
    @pasa to do that, you must be able to answer "what classes implement FooEnum" (which can't be done with standard java). Is that what you want? – Bohemian May 27 '16 at 19:38
  • Please, see latest question eddition. It contains two examples of what is expected. – pasaba por aqui May 28 '16 at 08:27
  • @pasabaporaqui see if the new implementation in my new answer suits better – Bohemian May 28 '16 at 23:25
  • Is it a tested solution? Because, after adapt it to Java 1.7, the result is an empty set. – pasaba por aqui May 29 '16 at 15:21
  • @pasabaporaqui it only works after the enum classes have been loaded, but this simple `main()` doesn't load them. If you use this in a normal server environment, it should work because other classes that use the enums will have been loaded before you check the content of the Set. Note that you don't have to reference each enum instance, just the class itself. – Bohemian May 29 '16 at 19:46