Вы действительно можете расширить Consumer (и Function и т.д.) с помощью нового интерфейса, который обрабатывает исключения, используя методы по умолчанию Java 8!
@Override defaultvoidaccept(final T elem) { try { acceptThrows(elem); } catch (final Exception e) { // Implement your own exception handling logic here.. // For example: System.out.println("handling an exception..."); // Or ... thrownewRuntimeException(e); } }
voidacceptThrows(T elem)throws Exception;
}
Тогда, например, если у вас есть список:
final List<String> list = Arrays.asList("A", "B", "C");
Если вы хотите использовать ее (например, с помощью forEach) с каким-либо кодом, который генерирует исключения, вы бы традиционно настроили блок try / catch:
final Consumer<String> consumer = aps -> { try { // maybe some other code here... thrownewException("asdas"); } catch (final Exception ex) { System.out.println("handling an exception..."); } }; list.forEach(consumer);
Но с этим новым интерфейсом вы можете создать его экземпляр с помощью лямбда-выражения, и компилятор не будет жаловаться:
final ThrowingConsumer<String> throwingConsumer = aps -> { // maybe some other code here... thrownewException("asdas"); }; list.forEach(throwingConsumer);
Или даже просто используйте ее, чтобы быть более краткой!:
list.forEach((ThrowingConsumer<String>) aps -> { // maybe some other code here... thrownewException("asda"); });
Обновить
Похоже, в состав Durian входит очень хорошая служебная библиотека под названием Errors, которая может быть использована для решения этой проблемы с гораздо большей гибкостью. Например, в моей реализации выше я явно определил политику обработки ошибок (System.out... или throw RuntimeException), тогда как ошибки Durian позволяют применять политику "на лету" с помощью большого набора служебных методов. Спасибо, что поделились этим, @NedTwigg!.
При переносе метода, возвращающего значение, существует важное различие между указанием значения по умолчанию или повторным переносом исключения RuntimeException .