Питання 26 · Розділ 19

Що робить метод join() і чим він відрізняється від get()

У get() є версія з таймаутом: get(5, TimeUnit.SECONDS). У join() — НЕМАЄ таймаут-варіанту. У production-коді, де потрібен таймаут, використовуйте get() або обгортайте join() чер...

Мовні версії: English Russian Ukrainian

🟢 Junior Level

join() і get() — обидва очікують завершення CompletableFuture і повертають результат.

Головна відмінність:

  • get() — викидає checked виключення (InterruptedException, ExecutionException)
  • join() — викидає unchecked (CompletionException)
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "Hello");

// get() — потрібен try-catch
try {
    String result = cf.get();  // throws checked exceptions
} catch (InterruptedException | ExecutionException e) {
    // handle
}

// join() — простіше
String result = cf.join();  // throws CompletionException (unchecked)

🟡 Middle Level

Коли що використовувати

get() — коли потрібні checked виключення:

try {
    String result = cf.get(5, TimeUnit.SECONDS);  // з таймаутом
} catch (TimeoutException e) {
    // timeout handling
} catch (InterruptedException e) {
    // interrupt handling
}

Критична практична відмінність

У get() є версія з таймаутом: get(5, TimeUnit.SECONDS). У join() — НЕМАЄ таймаут-варіанту. У production-коді, де потрібен таймаут, використовуйте get() або обгортайте join() через orTimeout().

join() — для ланцюжків і тестів:

// У ланцюжках
CompletableFuture.allOf(cf1, cf2, cf3)
    .thenApply(v -> {
        String r1 = cf1.join();  // не потрібно try-catch
        String r2 = cf2.join();
        String r3 = cf3.join();
        return combine(r1, r2, r3);
    });

// В тестах
@Test
void test() {
    String result = cf.join();  // простіше
    assertEquals("expected", result);
}

Типові помилки

  1. join() без обробки помилок: ```java // ❌ Якщо CF впаде — CompletionException String result = cf.join(); // може викинути

// ✅ З обробкою cf.exceptionally(ex -> “fallback”) .join(); // безпечно


---

## 🔴 Senior Level

### Internal Implementation

```java
// Спрощене представлення. Реальні методи в JDK можуть відрізнятися.
public T get() throws InterruptedException, ExecutionException {
    Object r = reportGet();
    if (r instanceof AltResult alt) {
        if (alt.ex != null) throw new ExecutionException((Throwable) alt.ex);
    }
    return (T) r;
}

public T join() {
    Object r = reportGet();
    if (r instanceof AltResult alt) {
        if (alt.ex != null) throw new CompletionException((Throwable) alt.ex);
    }
    return (T) r;
}

// Різниця тільки в типі виключення!

Performance

get(): ~100 ns (checked exception handling)
join(): ~100 ns (same internals)

Різниця negligible — вибір за зручністю

Best Practices

// ✅ join() у ланцюжках
cf.thenApply(v -> cf2.join());

// ✅ join() в тестах
assertEquals("expected", cf.join());

// ✅ get(timeout) для production
cf.get(5, TimeUnit.SECONDS);

// ❌ join() без обробки помилок
// ❌ get() без таймауту в production

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • join() — unchecked CompletionException, get() — checked InterruptedException + ExecutionException
  • join() НЕМАЄ таймауту, get(timeout, unit) Є таймаут
  • join() перевагіший у ланцюжках і тестах, get(timeout) для production
  • Внутрішньо однакові — різниця тільки в типі виключення
  • Обидва блокують потік до завершення CF

Часті уточнюючі питання:

  • join() або get() — коли що? — join() у ланцюжках/тестах, get(timeout) у production
  • join() може викинути TimeoutException? — Ні. Потрібен orTimeout() перед join()
  • CompletionException vs ExecutionException? — CompletionException (join) — unchecked, ExecutionException (get) — checked
  • join() після allOf() блокує? — Ні, якщо allOf() завершений. Але join() без allOf() — блокує

Червоні прапорці (НЕ говорити):

  • «join() неблокуючий» — блокує до завершення CF
  • «get() і join() повністю ідентичні» — різні типи виключень, get має таймаут
  • «join() без timeout у production — ок» — нескінченне очікування при помилці

Пов’язані теми:

  • [[20. Як реалізувати timeout для CompletableFuture]]
  • [[23. Як тестувати код з CompletableFuture]]
  • [[6. Як обробляти виключення в ланцюжку CompletableFuture]]
  • [[14. Що таке блокуючий код і як його відрізнити від неблокуючого]]