Как создать исключение внутри лямбда-выражения?

#java

#java

Вопрос:

Как создать исключение внутри лямбда-выражения, например, в ifPresentOrElse качестве необязательного?

 try {
   foo.bar(baz).ifPresentOrElse(theBar -> { 
      // A code inside here needs to throw a custom exception so the outside can handle it
      // It can't throw atm, and it is an unhandled exception here
   }, () -> { response.set(notFound()); }
} catch(CustomException e) {
  somethingImportantWhenExceptionIsThrown();
}
  

Комментарии:

1. Почему бы не использовать orElseThrow ?

2. Я имею в виду, что мне нужно, чтобы оно выбрасывалось изнутри, bar метод для выброса.

Ответ №1:

Хотя в вашем вопросе явно не указано, я предполагаю, что вы намерены создать проверенное исключение из ifPresentOrElse .

Во-первых, вы должны попытаться понять, почему вы не можете создать исключение. Consumer Интерфейс имеет, как Runnable , только один абстрактный метод, что делает его @FunctionalInterface . Из документации:

Обратите внимание, что экземпляры функциональных интерфейсов могут быть созданы с помощью лямбда-выражений, ссылок на методы или ссылок на конструкторы.

Это сокращенная версия Consumer интерфейса:

 public interface Consumer<T> {

    void accept(T t); // <-- NO throws Exception
}
  

В качестве альтернативы вы все еще можете использовать старый анонимный внутренний класс:

 Consumer<Object> consumer = new Consumer<>() {
    @Override
    public void accept(Object o) { // <-- NO throws Exception
       // consume
    }
};
  

Следовательно, вы не можете создать проверенное исключение из accept метода. Это невозможно по дизайну. Однако вы можете выбрать один из следующих вариантов:

  • Не рекомендуется использовать пользовательский ThrowingConsumer и ThrowingOptional класс, который может генерировать исключения (поскольку вы объявляете их в сигнатурах методов).
  • Оберните проверенное исключение в a RuntimeException , которое не нужно объявлять в сигнатуре метода и, следовательно, может быть выдано.
  • Перепишите свой код, чтобы не использовать лямбда-выражение.

Например, для последней точки:

 Optional<Bar> barOpt = foo.bar(baz);
if(bar.isPresent()) {
    Bar bar = barOpt.get();
    try {
        // code that throws checked exception
    } catch(CustomException e) {
        somethingImportantWhenExceptionIsThrown();
    }
} else {
    response.set(notFound());
} 
  

Комментарии:

1. 4) Используйте хак , предоставленный @quarks, но вам решать, хотите ли вы использовать Lombok.

Ответ №2:

Решением для этого является использование Project Lombok:

И аннотируйте метод, обертывающий эту функцию SneakyThrows , как таковой:

 @SneakyThrows
void method() {
   try {
       foo.bar(baz).ifPresentOrElse(theBar -> { 
          throw()
       }, () -> { response.set(notFound()); }
   } catch(CustomException e) {
      somethingImportantWhenExceptionIsThrown();
   }
}
  

Ответ №3:

Вы можете сделать это с помощью библиотеки apache commons-lang3.

https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html

 Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -> {
    throw new Exception();
}), () -> {});