I upgraded to Java 8 and tried to replace a simple iteration through a Map with a new lamdba expression. The loop searches for null values and throws an exception if one is found. The old Java 7 code looks like this:
for (Map.Entry<String, String> entry : myMap.entrySet()) {     if(entry.getValue() == null) {         throw new MyException("Key '" + entry.getKey() + "' not found!");     } }   And my attempt to convert this to Java 8 looks like this:
myMap.forEach((k,v) -> {     if(v == null) {         // OK         System.out.println("Key '" + k+ "' not found!");          // NOK! Unhandled exception type!         throw new MyException("Key '" + k + "' not found!");     } });   Can anyone explain why the throw statement not allowed here and how this could be corrected?
Eclipse's quick-fix suggestion does not look right to me... it simply surrounds the throw statement with a try-catch block:
myMap.forEach((k,v) -> {     if(v == null) {         try {             throw new MyException("Key '" + k + "' not found!");         }         catch (Exception e) {             e.printStackTrace();         }     } }); 
                A lambda expression cannot throw any checked exception until its corresponding functional interface declares a throws clause. An exception thrown by any lambda expression can be of the same type or sub-type of the exception declared in the throws clause of its functional interface.
A lambda expression body can't throw any exceptions that haven't specified in a functional interface. If the lambda expression can throw an exception then the "throws" clause of a functional interface must declare the same exception or one of its subtype.
The most straightforward way would be to use a try-catch block, wrap the checked exception into an unchecked exception and rethrow it: List<Integer> integers = Arrays. asList(3, 9, 7, 0, 10, 20); integers. forEach(i -> { try { writeToFile(i); } catch (IOException e) { throw new RuntimeException(e); } });
Fortunately, you can assign lambda expressions to variables and reuse them, as you would with objects.
You are not allowed to throw checked exceptions because the accept(T t, U u) method in the java.util.function.BiConsumer<T, U> interface doesn't declare any exceptions in its throws clause. And, as you know, Map#forEach takes such a type.
public interface Map<K, V> {      default void forEach(BiConsumer<? super K, ? super V> action) { ... }  }                        |                          |                          V @FunctionalInterface public interface BiConsumer<T, U> {      void accept(T t, U u); // <-- does throw nothing  }   That is true when we are talking about checked exceptions. But you still can throw an unchecked exception (e.g. a java.lang.IllegalArgumentException):
new HashMap<String, String>()     .forEach((a, b) -> { throw new IllegalArgumentException(); }); 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With