As far as I know, one could not handle exception thrown in the lambda if the abstract method implemented by the lambda doesn't have throws
in its signature.
I encountered following code, it works. Why openStream()
doesn't demand handling IOException
? I can see try-catch
in the tryWithResources
but I don't understand the mechanism behind it.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Function;
import java.util.function.Supplier;
public class Main {
public static <AUTOCLOSEABLE extends AutoCloseable, OUTPUT> Supplier<OUTPUT> tryWithResources(
Callable<AUTOCLOSEABLE> callable, Function<AUTOCLOSEABLE, Supplier<OUTPUT>> function,
Supplier<OUTPUT> defaultSupplier) {
return () -> {
try (AUTOCLOSEABLE autoCloseable = callable.call()) {
return function.apply(autoCloseable).get();
} catch (Throwable throwable) {
return defaultSupplier.get();
}
};
}
public static <INPUT, OUTPUT> Function<INPUT, OUTPUT> function(Supplier<OUTPUT> supplier) {
return i -> supplier.get();
}
public static void main(String... args) {
Map<String, Collection<String>> anagrams = new ConcurrentSkipListMap<>();
int count = tryWithResources(
() -> new BufferedReader(new InputStreamReader(
new URL("http://www.puzzlers.org/pub/wordlists/unixdict.txt").openStream())),
reader -> () -> reader.lines().parallel().mapToInt(word -> {
char[] chars = word.toCharArray();
Arrays.parallelSort(chars);
String key = Arrays.toString(chars);
Collection<String> collection = anagrams.computeIfAbsent(key, function(ArrayList::new));
collection.add(word);
return collection.size();
}).max().orElse(0), () -> 0).get();
anagrams.values().stream().filter(ana -> ana.size() >= count).forEach((list) -> {
for (String s : list)
System.out.print(s + " ");
System.out.println();
});
}
}
I've simplified your example to the core part:
public static void main(String[] args) {
withCallable(() -> new URL("url").openStream()); // compiles
withSupplier(() -> new URL("url").openStream()); // does not compile
}
public static <T> void withCallable(Callable<T> callable) { }
public static <T> void withSupplier(Supplier<T> callable) { }
If you try with this, you will see that withCallable
will compile fine but that withSupplier
does not compile; even if the lambda expression is compatible with the signature of both functional interfaces.
The reason behind this is that the functional method of the Callable
interface, which is call()
, declares throws Exception
in its signature. Supplier.get()
does not.
Quoting the JLS section 11.2.3:
It is a compile-time error if a lambda body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the function type targeted by the lambda expression.
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