Compilation failed due to an unannounced exception, even if it is declared

This method gives me a compilation, and I don't understand why:

private void invokeMethods(Object instance, List<Method> methods) throws InvocationTargetException, IllegalAccessException { methods.forEach(method -> method.invoke(instance)); } 

Error message:

Unconfirmed java.lang.IllegalAccessException exception; must be caught or declared abandoned

What does not make sense: the exception has already been declared thrown.

IntelliJ cannot fix it either. In intent actions, if I select Add exceptions to the method signature , it does nothing.

What am I missing? (I'm new to Java 8)

+5
source share
2 answers

The problem is that it is lambda that throws an exception, and the lambda used in forEach is not declared to throw an exception. See Consumer documentation.

The best way to solve this problem is to use the old form for each cycle:

 for (Method method : methods) { method.invoke(instance); } 

Although you can use something like this:

 methods.forEach(method -> { try { method.invoke(instance); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } }); 

In my opinion this really will not help, because you can no longer throw the same exception from lambda, you have to wrap it in a RuntimeException , which is not so nice ...

IntelliJ cannot fix it either. In intent actions, if I choose the Add Exceptions to Signature method, it does nothing.

The reason IntelliJ cannot do this is because it is part of the Consumer interface, which is part of the JDK. IntelliJ has no way to change this. Of course, IntelliJ could handle this better.

Conclusion:

There are times when lambdas are useful, and there are times when old ways to do things better.

+13
source

(method -> method.invoke(instance)) is a lambda expression, and this expression can throw an IllegalAccessException | InvocationTargetException IllegalAccessException | InvocationTargetException , you can surround it in try/catch

  methods.forEach(method -> { try { method.invoke(instance); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); // or throw new RuntimeException(e); } }); 

If you don't want to handle exception in lambda just use

 for (Method method : methods) { method.invoke(method); } 
0
source

Source: https://habr.com/ru/post/1209674/


All Articles