Stack Exchange
How to define an enum with zero or more Consumers operating on implementations of a common interface?
I have something like the below code (simplified as much as possible), which compiles:
class Test {

  enum TestEnum {
    ELEMENT1(Test::methodUsingTestclass1);

    <T extends TestInterface> TestEnum(Consumer<T>... consumers) {
    }
  }

  static void methodUsingTestclass1(TestClass1 testClass1) {
  }

  static void methodUsingTestclass2(TestClass2 testClass2) {
  }

  interface TestInterface {
  }

  class TestClass1 implements TestInterface {
  }

  class TestClass2 implements TestInterface {
  }

}

Now I want to be able to specify a vararg of Consumers in my enum:
enum TestEnum {
  ELEMENT1(Test::methodUsingTestclass1, Test::methodUsingTestclass2);

  <T extends TestInterface> TestEnum(Consumer<T>... consumers) {
  }
}

This no longer compiles:

Type parameter T has incompatible upper bounds: Test.TestClass1 and Test.TestClass2

T implements TestInterface, and I would like to define one or more Consumers operating on T. In other words, a list of method references to methods accepting an implementation class of TestInterface.
I have tried this:
enum TestEnum {
  ELEMENT1(Test::methodUsingTestclass1, Test::methodUsingTestclass2);

  <T extends TestInterface> TestEnum(Consumer<? extends T>... consumers) {
  }
}

But I still get the same compile error.
How can the code be modified so that its constructor accepts zero or more Consumers operating on different implementations of TestInterface?

The problem is, methodUsingTestclass1 is not a kind of Consumer<TestInterface>. Namely, it can't consume a TestClass2, which a  Consumer<TestInterface> should be able to do.

@Sweeper So, what I want is something like Consumer<T extends TestInterface>, which would be able to consume both TestClass1 and TestClass2. But I can't get my head around how to express this in code.

Even if you could do that, wherever the parameter consumers would be used, there would not be enough context for you to send the correct parameter accepted by that consumer. The first test for you is: show us how you use these Consumer<T>... consumers from within the enum, you'll see the problem.

Consumer<TestInterface> is such a type of consumer. But note that Test::methodUsingTestclass1 is not an instance of this type, because the method can only consume TestClass1, not "both TestClass1 and TestClass2" How do you intend on using this array of consumers?

I suspect this is a case of context lost in the introduction of the MVCE. If you're really using these consumers in the enum, then you're probably using a different interface than Consumer. Because for the difference between methodUsingTestclass1 and methodUsingTestclass2 to be meaningful at invocation time, the functional interface type must be sensitive to concrete TestInterface argument. Consumer just doesn't have this notion.

@ernest_k It is. In fact I am using an own FunctionalInterface accepting three parameters and returning a String. Which makes it hard for me to show how I itend to use it without fully modifying the question... I tried to keep it simple. But I see what you are saying, and perhaps I just need to rethink my implementation a bit.

If you accept Consumer<? extends TestInterface>... and pass in ELEMENT1((Consumer<? extends TestInterface>)(Consumer<TestClass1>)Test::methodUsingTestclass1, (Consumer<? extends TestInterface>)(Consumer<TestClass2>)Test::methodUsingTestclass2); It works. But you can't do anything with the consumers because you don't know what each consumer can accept anymore. You only know that they all accept some implementation of TestInterface, which is not enough information for you to be able to pass something into it.
