partha
partha

Reputation: 2316

Coding to generics type

I have a slightly odd issue with Java generics. Actually it might not be an issue at all and it might just me that I am trying to use generics incorrectly in design. I will not give the entire details of the application (it is irrelevant and boring).

I have created a small snippet that captures the essence of the problem.

There is a Producer interface which looks like this.

public interface Producer<P> {
public P produce(); 
}

There is an implementation of this interface which looks like this

public class IntegerProducer<P> implements Producer<P> {

@Override
public P produce() {
    return (P)new Integer(10);
}
}

What I really need to do in the produce method is something like

if (P instanceOf Integer) return (P)new Integer(10);
else throw new Exception("Something weird happened in the client app"); 

Now of course the P instanceOf Integer won't work. But if you have got the essence of what I am trying to do, would you please share a solution.

Thanks for helping.

Clarification 1: The issue is not that I want to return Integer only. The issue is that in the function produce(), I need to check the type of generics used by the client program and change the behaviour of the function based on that. It is not that I want to restrict the type of generics used to a particular type of Object (where I could have used wildcards) but I need the function produce() to behave slightly differently based on the kind of Object used in the generics by the client code.

Upvotes: 3

Views: 57

Answers (1)

assylias
assylias

Reputation: 328598

How about:

public class IntegerProducer implements Producer<Integer> {

    @Override
    public Integer produce() {
        return 10;
    }
}

Since your IntegerProducer deals with Integers only, you don't need it to be generic. You can then write:

Producer<Integer> p = new IntegerProducer();
Integer i = p.produce();

EDIT

Following your comment, I think the only way would be to pass a class parameter:

public class Producer<T> {

    public static void main(String[] args) throws InterruptedException {
        Producer<Integer> t1 = new Producer<> ();
        Producer<String> t2 = new Producer<> ();
        System.out.println(t1.get(Integer.class)); //prints 10
        System.out.println(t1.get(String.class)); //does not compile
        System.out.println(t2.get(String.class)); //throws exception
    }

    public T get(Class<T> c) {
        if (c == Integer.class) {
            return (T) (Object) 10;
        }
        throw new UnsupportedOperationException();
    }
}

Alternatively you can pass it in the constructor (strategy used for example by EnumSets and EnumMaps):

public class Producer<T> {

    public static void main(String[] args) throws InterruptedException {
        Producer<Integer> t1 = new Producer<> (Integer.class);
        Producer<Integer> t1 = new Producer<> (String.class); //does not compile
        Producer<String> t2 = new Producer<> (String.class);
        System.out.println(t1.get()); //prints 10
        System.out.println(t2.get()); //throws exception
    }

    private final Class<T> c;

    public Producer(Class<T> c) {
        this.c = c;
    }

    public T get() {
        if (c == Integer.class) {
            return (T) (Object) 10;
        }
        throw new UnsupportedOperationException();
    }
}

That clearly clutters the code and I would personally reconsider the design to avoid that kind of situation.

Upvotes: 10

Related Questions