Functional
Optional: orElse と orElseGet は既定値の評価タイミングが違う
orElse は値があっても引数を評価し、orElseGet は必要になるまで Supplier を呼びません。
SourceOptionalFallbacks.java
Java 21
package examples.optional;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
public final class OptionalFallbacks {
private OptionalFallbacks() {}
public static String withOrElse(Optional<String> value, AtomicInteger fallbackCalls) {
return value.orElse(fallback(fallbackCalls));
}
public static String withOrElseGet(Optional<String> value, AtomicInteger fallbackCalls) {
return value.orElseGet(() -> fallback(fallbackCalls));
}
private static String fallback(AtomicInteger fallbackCalls) {
fallbackCalls.incrementAndGet();
return "guest";
}
}TestOptionalFallbacksTest.java
Java 21
package examples.optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
class OptionalFallbacksTest {
@Test
void orElseはOptionalに値があっても引数を評価する() {
var fallbackCalls = new AtomicInteger();
var result = OptionalFallbacks.withOrElse(Optional.of("member"), fallbackCalls);
assertEquals("member", result);
assertEquals(1, fallbackCalls.get());
}
@Test
void orElseGetはOptionalに値がある場合Supplierを評価しない() {
var fallbackCalls = new AtomicInteger();
var result = OptionalFallbacks.withOrElseGet(Optional.of("member"), fallbackCalls);
assertEquals("member", result);
assertEquals(0, fallbackCalls.get());
}
}01Assertion
このテストで確認できること
- 値がある Optional でも orElse の引数評価は実行される
- 値がある Optional では orElseGet の Supplier は実行されない
既定値の生成がDBアクセスや重い処理なら、値がある場合に余計な仕事をしない orElseGet を使います。
OBSERVED RESULT
expected: orElse fallback calls → 1
actual: 1
expected: orElseGet calls → 0
actual: 0