I know how to create a reference to a method that has a String parameter and returns an int, it\'s:
Function
Create a custom return type that will propagate the checked exception. This is an alternative to creating a new interface that mirrors the existing functional interface with the slight modification of a "throws exception" on the functional interface's method.
public static interface CheckedValueSupplier {
public V get () throws Exception;
}
public class CheckedValue {
private final V v;
private final Optional opt;
public Value (V v) {
this.v = v;
}
public Value (Exception e) {
this.opt = Optional.of(e);
}
public V get () throws Exception {
if (opt.isPresent()) {
throw opt.get();
}
return v;
}
public Optional getException () {
return opt;
}
public static CheckedValue returns (T t) {
return new CheckedValue(t);
}
public static CheckedValue rethrows (Exception e) {
return new CheckedValue(e);
}
public static CheckedValue from (CheckedValueSupplier sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
return Result.rethrows(e);
}
}
public static CheckedValue escalates (CheckedValueSupplier sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// Don't use this pattern with FileReader, it's meant to be an
// example. FileReader is a Closeable resource and as such should
// be managed in a try-with-resources block or in another safe
// manner that will make sure it is closed properly.
// This will not compile as the FileReader constructor throws
// an IOException.
Function sToFr =
(fn) -> new FileReader(Paths.get(fn).toFile());
// Alternative, this will compile.
Function> sToFr = (fn) -> {
return CheckedValue.from (
() -> new FileReader(Paths.get("/home/" + f).toFile()));
};
// Single record usage
// The call to get() will propagate the checked exception if it exists.
FileReader readMe = pToFr.apply("/home/README").get();
// List of records usage
List paths = ...; //a list of paths to files
Collection> frs =
paths.stream().map(pToFr).collect(Collectors.toList());
// Find out if creation of a file reader failed.
boolean anyErrors = frs.stream()
.filter(f -> f.getException().isPresent())
.findAny().isPresent();
A single functional interface that throws a checked exception is created (CheckedValueSupplier). This will be the only functional interface which allows checked exceptions. All other functional interfaces will leverage the CheckedValueSupplier to wrap any code that throws a checked exception.
The CheckedValue class will hold the result of executing any logic that throws a checked exception. This prevents propagation of a checked exception until the point at which code attempts to access the value that an instance of CheckedValue contains.
CheckedValue#get() is called.Some functional interfaces (Consumer for example) must be handled in a different manner as they don't provide a return value.
One approach is to use a function instead of a consumer, which applies when handling streams.
List lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
.map(e -> CheckedValueSupplier.from(
() -> {throwyMethod(e); return e;}))
.filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior
Alternatively, you can always escalate to a RuntimeException. There are other answers that cover escalation of a checked exception from within a Consumer.
Just avoid functional interfaces all together and use a good-ole-fashioned for loop.