Erstellen Sie einen benutzerdefinierten Rückgabetyp, der die aktivierte Ausnahme weitergibt. Dies ist eine Alternative zum Erstellen einer neuen Schnittstelle, die die vorhandene Funktionsschnittstelle widerspiegelt, wobei die Methode der Funktionsschnittstelle geringfügig geändert wird.
Definition
CheckedValueSupplier
public static interface CheckedValueSupplier<V> {
public V get () throws Exception;
}
CheckedValue
public class CheckedValue<V> {
private final V v;
private final Optional<Exception> 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<Exception> getException () {
return opt;
}
public static <T> CheckedValue<T> returns (T t) {
return new CheckedValue<T>(t);
}
public static <T> CheckedValue<T> rethrows (Exception e) {
return new CheckedValue<T>(e);
}
public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
return Result.rethrows(e);
}
}
public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Verwendungszweck
// 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<String, FileReader> sToFr =
(fn) -> new FileReader(Paths.get(fn).toFile());
// Alternative, this will compile.
Function<String, CheckedValue<FileReader>> 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<String> paths = ...; //a list of paths to files
Collection<CheckedValue<FileReader>> 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();
Was ist los?
Eine einzelne Funktionsschnittstelle, die eine aktivierte Ausnahme auslöst, wird erstellt ( CheckedValueSupplier
). Dies ist die einzige funktionale Schnittstelle, die geprüfte Ausnahmen zulässt. Alle anderen Funktionsschnittstellen nutzen das CheckedValueSupplier
, um Code zu verpacken, der eine aktivierte Ausnahme auslöst.
Die CheckedValue
Klasse enthält das Ergebnis der Ausführung einer Logik, die eine aktivierte Ausnahme auslöst. Dies verhindert die Weitergabe einer aktivierten Ausnahme bis zu dem Punkt, an dem Code versucht, auf den Wert zuzugreifen, den eine Instanz CheckedValue
enthält.
Die Probleme mit diesem Ansatz.
- Wir werfen jetzt "Ausnahme" und verbergen effektiv den ursprünglich geworfenen spezifischen Typ.
- Uns ist nicht bekannt, dass eine Ausnahme aufgetreten ist, bis sie
CheckedValue#get()
aufgerufen wird.
Consumer et al
Einige funktionale Schnittstellen ( Consumer
zum Beispiel) müssen anders behandelt werden, da sie keinen Rückgabewert liefern.
Funktion anstelle des Verbrauchers
Ein Ansatz besteht darin, anstelle eines Verbrauchers eine Funktion zu verwenden, die bei der Verarbeitung von Streams angewendet wird.
List<String> 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
Eskalieren
Alternativ können Sie jederzeit zu a eskalieren RuntimeException
. Es gibt andere Antworten, die die Eskalation einer aktivierten Ausnahme innerhalb von a abdecken Consumer
.
Nicht konsumieren.
Vermeiden Sie einfach alle funktionalen Schnittstellen und verwenden Sie eine altmodische for-Schleife.