İşaretli özel durumu çoğaltacak özel bir dönüş türü oluşturun. Bu, fonksiyonel arabirimin yönteminde bir "istisna atar" ufak bir değişiklikle mevcut işlevsel arabirimi yansıtan yeni bir arabirim oluşturmaya bir alternatiftir.
Tanım
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);
}
}
}
kullanım
// 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();
Neler oluyor?
İşaretli bir istisna atan tek bir işlevsel arabirim oluşturulur ( CheckedValueSupplier
). Bu, kontrol edilen istisnalara izin veren tek işlevsel arayüz olacaktır. Diğer tüm işlevsel arabirimler, CheckedValueSupplier
denetlenen bir özel durum oluşturan herhangi bir kodu sarmak için kullanılır.
CheckedValue
Sınıf bir kontrol istisna atar herhangi bir mantık yürütme sonucunu tutacaktır. Bu, kodun bir örneğinin CheckedValue
içerdiği değere erişmeye çalıştığı noktaya kadar işaretli bir istisnanın yayılmasını önler .
Bu yaklaşımla ilgili sorunlar.
- Şimdi atılan spesifik türü etkili bir şekilde gizleyerek "İstisna" yı atıyoruz.
- Şu ana kadar istisna oluştuğunun farkında değiliz
CheckedValue#get()
.
Tüketici ve ark.
Bazı fonksiyonel arayüzler (Consumer
örneğin) bir dönüş değeri sağlamadığından farklı bir şekilde ele alınmalıdır.
Tüketici yerine işlev
Bir yaklaşım, akışları ele alırken geçerli olan tüketici yerine bir işlev kullanmaktır.
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
kızıştırmak
Alternatif olarak, her zaman a'ya yükseltebilirsiniz RuntimeException
. İşaretli bir kural dışı durumun a Consumer
.
Tüketim.
Fonksiyonel arayüzleri bir arada kullanmaktan kaçının ve döngü için iyi bir ole tarzı kullanın.