-1

I want to create a generic inner class for opening streams of different types. Towards this end I did the following:

private class StreamOpener<T1, T2>
{
    StreamOpener(String fileName, T1 v1)
    {
        v1 = null;

        try
        {
            v1 = new T1(new T2(fileName));
        }
        catch (FileNotFoundException e)
        {
            System.err.println("File " + fileName + " not found.  Exiting");
            System.exit(-1);
        }
        catch (Exception e)
        {
            System.err.println("Error on file " + fileName + "  Exiting");
            System.exit(-1);
        }
    }
}   

The idea is that, for example, for reading text files T1 could be Scanner and T2 could be FileInputStream. Similartly, for writing text files, T1 could be PrintWriter and T2 could be FileOutputStream.

However, I am getting a compile error at the following line: v1 = new T1(new T2(fileName));

Is there a way out?

Sandeep
  • 787
  • 4
  • 20

1 Answers1

1

You can't do exactly what you have posted, because in Java generics are not reified. However, you can modify your example using type tokens, although this is rather ugly. For example:

private class StreamOpener<T1, T2>
{
    T1 v1;

    StreamOpener(String fileName, Class<T1> t1Class, Class<T2> t2Class)
    {
        try
        {
            Constructor<T2> t2Constructor = t2Class.getConstructor(String.class);
            T2 v2 = t2Constructor.newInstance(fileName);
            Constructor<T1> t1Constructor = t1Class.getConstructor(t2Class);
            v1 = constructor.newInstance(v2);
        }
        catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) // yuck
        {
           System.err.println("Reflection error, fire your programmer");
           System.exit(-1);
        }
        catch (FileNotFoundException e)
        {
            System.err.println("File " + fileName + " not found.  Exiting");
            System.exit(-1);
        }
        catch (Exception e)
        {
            System.err.println("Error on file " + fileName + "  Exiting");
            System.exit(-1);
        }
    }
}   

However, the above is pretty awful code. Instead, you could delegate the creation of T1 to some interface like this:

interface StreamCreator<T> {
    T open() throws Exception; // code smell
}

Then, you could invoke this whenever you need an object. One implementation might return new Scanner(new InputStream(fileName)). Another implementation could return new PrintWriter(new FileOutputStream(fileName)). And since it's a functional interface, you can define implementations inline with lambdas, in Java 8.

On the other hand, I'm struggling to figure out why you would want to do this in the first place. A Scanner and a PrintWriter expose two totally different interfaces. So how would it be useful to make a single function that could create both of them, in different ways? The calling code would have to be specific to either a Scanner or a PrintWriter, so why not just create the Scanner or PrintWriter using two separate methods?

Eric Galluzzo
  • 3,066
  • 1
  • 17
  • 20