Bạn có thể thử này:
void deleteEntity(Node node) throws SomeException { node.getChildren().forEach(UtilException.rethrowConsumer(this::deleteChild));
}
Lớp UtilException
helper bên dưới cho phép bạn sử dụng bất kỳ kiểm tra ngoại lệ trong Java suối. Lưu ý rằng luồng trên cũng ném ngoại lệ đã kiểm tra ban đầu được ném bởi this::deleteChild
và KHÔNG bao gồm một số ngoại lệ được bỏ chọn.
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; }
}
Nhiều ví dụ khác về cách sử dụng nó (sau khi tĩnh nhập khẩu 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");
}
Nhưng đừng sử dụng nó trước khi tìm hiểu những ưu điểm, nhược điểm và hạn chế sau:
• Nếu mã gọi là xử lý ngoại lệ đã kiểm tra, bạn phải thêm nó vào mệnh đề ném của phương thức chứa luồng. Trình biên dịch sẽ không buộc bạn thêm nó nữa, vì vậy sẽ dễ dàng quên nó hơn.
• Nếu mã gọi đã xử lý ngoại lệ đã chọn, trình biên dịch S remind nhắc bạn thêm mệnh đề ném vào khai báo phương thức có chứa luồng (nếu bạn không nói: Ngoại lệ không bao giờ được ném vào phần thân của câu lệnh try tương ứng).
• Trong mọi trường hợp, bạn sẽ không thể tự bao quanh luồng để bắt ngoại lệ được kiểm tra INSIDE phương thức chứa luồng (nếu bạn thử, trình biên dịch sẽ nói: Ngoại lệ không bao giờ được ném vào phần thân của câu lệnh thử tương ứng).
• Nếu bạn đang gọi một phương pháp có nghĩa là không bao giờ có thể ném ngoại lệ mà nó tuyên bố, thì bạn không nên bao gồm mệnh đề ném. Ví dụ: chuỗi mới (byteArr, "UTF-8") ném UnsupportedEncodingException, nhưng UTF-8 được đảm bảo bởi thông số Java để luôn có mặt. Ở đây, các tuyên bố ném là một phiền toái và bất kỳ giải pháp để im lặng nó với boilerplate tối thiểu được chào đón.
• Nếu bạn ghét các ngoại lệ đã kiểm tra và cảm thấy chúng không bao giờ được thêm vào ngôn ngữ Java để bắt đầu (số người ngày càng tăng theo cách này, và tôi KHÔNG là một trong số đó) ngoại lệ đã kiểm tra đối với điều khoản ném của phương thức chứa luồng. Sau đó, ngoại lệ được kiểm tra sẽ hoạt động giống như một ngoại lệ được kiểm tra.
• Nếu bạn đang triển khai giao diện nghiêm ngặt, nơi bạn không có tùy chọn thêm tuyên bố ném, và ném ngoại lệ là hoàn toàn thích hợp, sau đó bao gồm ngoại lệ chỉ để có được đặc quyền ném kết quả một stacktrace với ngoại lệ giả mạo mà đóng góp không có thông tin về những gì thực sự đã đi sai. Một ví dụ tốt là Runnable.run(), không ném bất kỳ ngoại lệ đã kiểm tra nào. Trong trường hợp này, bạn có thể quyết định không thêm ngoại lệ đã kiểm tra vào điều khoản ném của phương thức chứa luồng.
• Trong mọi trường hợp, nếu bạn quyết định không thêm (hoặc quên thêm) ngoại trừ kiểm tra để ném khoản của phương pháp có chứa các dòng, thể nhận thức được những 2 hậu quả của việc ném ngoại lệ CHECKED:
1) Mã gọi sẽ không thể bắt được bằng tên (nếu bạn thử, trình biên dịch sẽ nói: Ngoại lệ không bao giờ được ném vào phần thân của câu lệnh try tương ứng). Nó sẽ bong bóng và có thể được bắt trong vòng lặp chương trình chính bởi một số "bắt ngoại lệ" hoặc "bắt Throwable", mà có thể là những gì bạn muốn anyway.
2) Vi phạm nguyên tắc ít ngạc nhiên nhất: nó sẽ không còn đủ để bắt RuntimeException để có thể đảm bảo bắt tất cả ngoại lệ có thể xảy ra. Vì lý do này, tôi tin rằng điều này không nên được thực hiện trong mã khung công tác, nhưng chỉ trong mã doanh nghiệp mà bạn hoàn toàn kiểm soát.
Kết luận: Tôi tin rằng những hạn chế ở đây không nghiêm trọng và lớp học UtilException
có thể được sử dụng mà không sợ hãi. Tuy nhiên, tùy thuộc vào bạn!
Là một sang một bên, đây không phải là một biểu thức lambda - đó là một tham chiếu phương pháp. Nó sẽ là một biểu thức lambda nếu bạn sử dụng 'forEach (x -> deleteChild (x))'. Điều đó sẽ thất bại cho cùng một lý do mặc dù. –