dokaspar dokaspar - 1 month ago 9
Java Question

Why can't I throw an exception in a Java 8 lambda expression?

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();
}
}
});

Answer

You can't throw an exception because the void accept(T t, U u); method in the BiConsumer<T, U> interface doesn't throw any exceptions. And, as you know, forEach takes such type.

public 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's true if we're talking about checked exceptions. But you are allowed to throw an unchecked exception, for instance, an IllegalArgumentException:

new HashMap<String, String>()
    .forEach((a, b) -> { throw new IllegalArgumentException(); });
Comments