Как использовать результат thenCompose несколько раз в Java 8?

#java #java-8 #future #completable-future

#java #java-8 #будущее #завершаемый-будущее

Вопрос:

У меня есть серия thenCompose вызовов, похожих на

 myObject.updateDB(payload)
      .thenCompose(__ -> getUserID(payload.ID()))
      .thenCompose(id -> getProfile(id))
      .thenCompose(userProfile -> updateSomething(userProfile))
      .thenCompose(__ -> notifyUser(id))
      .thenAccept(__ -> doSomething())
      .exceptionally(t -> doSomethingElse());
  

getUserID Вызов возвращает a CompletionStage<String> , который я использую в следующем вызове getProfile . Мне нужно то же id самое снова для notifyUser вызова. Как сделать его доступным там? IDE показывает

Не удается разрешить идентификатор символа.

Ответ №1:

Проблема с вашим текущим кодом заключается в том, что к тому времени, когда вы достигнете .thenCompose(__ -> notifyUser(id)) , переменная id больше не находится в области видимости.

Простым решением в этом случае было бы вызвать multiple thenCompose непосредственно для CompletionStage возвращаемого getProfile :

 myObject.updateDB(payload)
  .thenCompose(__ -> getUserID(payload.ID()))
  .thenCompose(id -> 
      getProfile(id)
          .thenCompose(userProfile -> updateSomething(userProfile))
          .thenCompose(__ -> notifyUser(id))
  )
  // rest of chain calls
  

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

1. Это не простое решение. Простым решением было бы превратить эту compose общую цепочку в один блок кода. Нет никакой пользы в выражении этой полностью линейной последовательности на стольких этапах. Записывая его как одно действие, все необходимые значения находятся в области видимости, а также все эти неиспользуемые параметры исчезают…

Ответ №2:

Я думаю, ваш код становится проще, если вы не настаиваете на использовании thenCompose для каждого шага:

 myObject.updateDB(payload)
    .thenCompose(__ -> getUserID(payload.ID()))
    .thenAccept(id -> {
        updateSomething(getProfile(id).join());
        notifyUser(id);
    })
    .thenRun(() -> doSomething())
    .exceptionally(t -> doSomethingElse());
  

Если вам требуется эффективная последовательность каждого шага, вы можете просто использовать join :

 myObject.updateDB(payload)
    .thenCompose(__ -> getUserID(payload.ID()))
    .thenAccept(id -> {
        updateSomething(getProfile(id).join()).join();
        notifyUser(id).join();
    })
    .thenRun(() -> doSomething())
    .exceptionally(t -> doSomethingElse());
  

Учитывая, что вся цепочка эффективно последовательна, вы можете просто написать ее прямолинейно:

 myObject.updateDB(payload)
    .thenRun(() -> {
        YourUserIDType id = getUserID(payload.ID()).join();
        updateSomething(getProfile(id).join()).join();
        notifyUser(id).join();
        doSomething();
    })
    .exceptionally(t -> doSomethingElse());