Enforce class fields to be same generic type without specifying a class type parameter

Store the producer and consumer in an inner class with the type variable:

public class ProduceAndConsume {
  private class Inner<IntermediateType> {
    private Producer<? extends IntermediateType> producer;
    private Consumer<IntermediateType> consumer;

    // Constructor omitted.

    private void doLater() {
      consumer.consume(producer.produce());
    }
  }

  private final Inner<?> inner;

  public <IntermediateType> ProduceAndConsume(Producer<? extends IntermediateType> producer, Consumer<IntermediateType> consumer) {
    this.inner = new Inner<>(producer, consumer);
  }

  private void doLater() { // Or just invoke inner.doLater() directly.
    inner.doLater();  
  }
}

In this way, you enforce that the producer and consumer are related for when you need to use them later, but you don't need that type information afterwards in the ProduceAndConsume instance.

Producer<String> stringProducer = ...;
Consumer<Object> objConsumer = ...;

// No externally-visible type variables.
ProduceAndConsume pac1 = new ProduceAndConsume(stringProducer, objConsumer);

But the compiler enforces compatibility of the producer and consumer:

Consumer<Integer> integerConsumer = ...;
// Compiler error.
ProduceAndConsume pac2 = new ProduceAndConsume(stringProducer, integerConsumer);

Tags:

Java

Generics