Bu UtilException
yardımcı sınıf, Java akışlarında işaretli istisnaları şu şekilde kullanmanızı sağlar:
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
Kontrol edilen not Class::forName
atar . Akışın kendisi de atılır ve bazı kontrol edilmeyen istisna DEĞİLDİR.ClassNotFoundException
ClassNotFoundException
public final class UtilException {
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
void run() throws E;
}
/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
return t -> {
try { consumer.accept(t); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try { biConsumer.accept(t, u); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
return t -> {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
return () -> {
try { return function.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
{
try { t.run(); }
catch (Exception exception) { throwAsUnchecked(exception); }
}
/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
{
try { return supplier.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
Nasıl kullanılacağı ile ilgili diğer birçok örnek (statik olarak içe aktardıktan sonra UtilException
):
@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(System.out::println));
}
@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
List<Class> classes1
= Stream.of("Object", "Integer", "String")
.map(rethrowFunction(className -> Class.forName("java.lang." + className)))
.collect(Collectors.toList());
List<Class> classes2
= Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
}
@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
Collector.of(
rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
}
@Test
public void test_uncheck_exception_thrown_by_method() {
Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));
Class clazz2 = uncheck(Class::forName, "java.lang.String");
}
@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
Class clazz3 = uncheck(Class::forName, "INVALID");
}
Ancak aşağıdaki avantajları, dezavantajları ve sınırlamaları anlamadan kullanmayın :
• Eğer arama kodu işaretli istisnayı işleyecekse, akışı içeren yöntemin atma maddesine eklemeniz GEREKİR. Derleyici sizi artık eklemeye zorlamayacak, bu yüzden unutmak daha kolay.
Eğer arama kodu kontrol edilen istisnayı zaten ele alıyorsa, derleyici akışı içeren yöntem bildirimine atarma maddesini eklemenizi hatırlatacaktır (eğer söylemezseniz: İstisna asla karşılık gelen try ifadesinin gövdesine atılmaz) ).
• Her durumda, akışı içeren yöntemin İÇİNDE, denetlenen özel durumu yakalamak için akışın kendisini kuşatamazsınız (denerseniz, derleyici şunu söyler: İstisna asla karşılık gelen try ifadesinin gövdesine atılmaz).
• Asla beyan ettiği istisnayı hiçbir zaman atamayacak bir yöntem çağırıyorsanız, bu durumda atma cümleciklerini eklememelisiniz. Örneğin: yeni Dize (byteArr, "UTF-8") UnsupportedEncodingException oluşturur, ancak UTF-8'in Java spec tarafından her zaman mevcut olması garanti edilir. Burada, fırlatma bildirimi bir sıkıntıdır ve minimal kazan plakası ile susturmak için herhangi bir çözüm kabul edilir.
• İşaretli istisnalardan nefret ediyorsanız ve başlamak için Java diline asla eklenmemeleri gerektiğini düşünüyorsanız (giderek artan sayıda insan bu şekilde düşünüyor ve ben onlardan biri DEĞİLİM), o zaman işaretli istisnayı akışı içeren yöntemin yan tümcesini atar. Kontrol edilen istisna, tıpkı Kontrol Edilmemiş bir istisna gibi davranacaktır.
• Bir atış bildirimi ekleme seçeneğinizin bulunmadığı ve yine de bir istisna atmanın tamamen uygun olduğu katı bir arabirim uyguluyorsanız, yalnızca istisna atma ayrıcalığını sahtekarlık istisnalarıyla sonuçlandırmak için bir istisna sarmak aslında neyin yanlış gittiğine dair hiçbir bilgi içermiyor. Buna iyi bir örnek, kontrol edilen istisnaları atmayan Runnable.run () şeklindedir. Bu durumda, işaretli özel durumu akışı içeren yöntemin atarma yan tümcesine eklememeye karar verebilirsiniz.
• Her durumda, akışı içeren yöntemin atar yan tümcesine işaretli istisnayı eklememeye (veya eklemeyi unutmamaya) karar verirseniz, CHECKED istisnalarını atmanın şu 2 sonucunun farkında olun:
1) Arama kodu adı ile yakalayamaz (denerseniz, derleyici şunu söyleyecektir: İstisna asla karşılık gelen try ifadesinin gövdesine atılmaz). Kabarcık olacak ve muhtemelen ana program döngüsünde bazı "İstisna yakalamak" veya "Throwable yakalamak" tarafından yakalanır, bu da istediğiniz gibi olabilir.
2) En az sürpriz ilkesini ihlal eder: artık tüm olası istisnaları yakalamayı garanti edebilmek için RuntimeException'ı yakalamak yeterli olmayacaktır. Bu nedenle, bunun çerçeve kodunda değil, yalnızca tamamen kontrol ettiğiniz iş kodunda yapılması gerektiğine inanıyorum.
Sonuç olarak: Buradaki sınırlamaların ciddi olmadığına ve UtilException
sınıfın korkusuzca kullanılabileceğine inanıyorum. Ancak, size kalmış!