7

I am using Eclipse Luna Service Release 2 (4.4.2), Java 8 u51.

I'm trying to create a method which will create instances of a passed object based on another method parameter. The prototype is simplified to

public <T> T test(Object param, T instance) {
    Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor

    // eclipse reports "Unhandled exception type InvocationTargetException"
    Function<Object, Object> createFun = constructor::newInstance;

    T result = (T) createFun.apply(param);
    return result;
}

On line with Function declaration eclipse reports Unhandled exception type InvocationTargetException compiler error. I need the Function to later use in a stream.

I tried to add various try/catch blocks, throws declarations, but nothing fixes this compiler error.

How to make this code work?

Dariusz
  • 21,561
  • 9
  • 74
  • 114

2 Answers2

12

You can't throw a checked exception from a lambda with a Function target type because its apply method does not throw an exception. So you need to make it into an unchecked exception, for example by wrapping it:

Function<Object, Object> createFun = o -> {
  try {
    return constructor.newInstance(o);
  } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
    throw new RuntimeException(e);
  }
};

An alternative is to lead the compiler to think it's an unchecked exception, which produces a cleaner stack trace vs. the option above:

Function<Object, Object> createFun = o -> {
  try {
    return constructor.newInstance(o);
  } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
    return uncheck(e);
  }
};

With the following utility method:

@SuppressWarnings("unchecked")
public static <E extends Throwable, T> T uncheck(Throwable t) throws E {
  throw ((E) t);
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 3
    You can throw a checked exception from a lambda. But not from a lambda which is supposed to implement Function, because Function.apply() doesn't throw a checked exception. – JB Nizet Jul 17 '15 at 08:02
  • 2
    You could probably tighten up your `uncheck` method by introducing a `` bound, so you don't have to do any sorts of cast. You could also just perform your throw inside of the `uncheck` method, too; no need for two methods when you could just throw in one. – Makoto Jul 17 '15 at 08:04
4

This is because the Method Reference is to a Method with the Exceptions named in the compile time error. The single abstract Method R apply(T t ) in java.util.Function does not throw these Exceptions. So there is a mismatch between the functional type of java.util.Function and the type of your Method-Reference.

Using a functional type with a matching method works ... for example :

    interface MyFunction<T,R> {
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t) throws  Throwable;

    }

    public <T> T test(Object param, T instance) throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException {
        Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor

        // eclipse reports "Unhandled exception type InvocationTargetException"
            MyFunction<Object,Object> createFun = constructor::newInstance;

        T result = (T) createFun.apply(param);
        return result;
    }
André R.
  • 1,627
  • 10
  • 14