1

私は、Cay S. Horstmann 著の本「本当にせっかちな人のための Java SE 8」の演習に取り組んでいます。

メソッドを書く

public static <T> CompletableFuture<T> repeat(
         Supplier<T> action, Predicate<T> until)

これは、関数によって受け入れられる値が生成されるまでアクションを非同期的に繰り返しuntilます。これも非同期で実行する必要があります。コンソールからa を読み取る関数と java.net.PasswordAuthentication、1 秒間スリープしてからパスワードが「秘密」であることを確認することで有効性チェックをシミュレートする関数を使用してテストします。

次のコードを思いつきましたが、ランダムなパスワード生成戦略が失敗しているようです。すべてのスレッドが常に同じパスワードを選択しますが、これは非常に奇妙に思えます。

public static <T> CompletableFuture<T> repeat(final Supplier<T> action, final Predicate<T> until) {
    final CompletableFuture<T> futureAction = supplyAsync(action);
    final boolean isMatchFound = futureAction.thenApplyAsync(until::test).join();

    final T suppliedValue = getSuppliedValue(futureAction);

    if (isMatchFound) {
        LOGGER.info("Got a match for value {}.", suppliedValue);

        return futureAction;
    }

    return repeat(() -> suppliedValue, until);
}

private static <T> T getSuppliedValue(final CompletableFuture<T> futureAction) {
    try {
        return futureAction.get();
    } catch (InterruptedException | ExecutionException e) {
        LOGGER.error(e.getMessage());
    }

    return null;
}

テストケース:

@Test
public void testRepeat() {
    Supplier<PasswordAuthentication> action = () -> {
        final String[] passwordVault = new String[] { "password", "secret",
            "secretPassword" };

        final int len = passwordVault.length;

        return new PasswordAuthentication("mickeyMouse",
            passwordVault[ThreadLocalRandom.current().nextInt(len)].toCharArray());
    };
    @SuppressWarnings("static-access")
    Predicate<PasswordAuthentication> until = passwordAuth -> {
        try {
            currentThread().sleep(1000);
        } catch (InterruptedException e) {
            fail(e.getMessage());
        }

        final String password = String.valueOf(passwordAuth.getPassword());

        LOGGER.info("Received password: {}.", password);

        return password.equals("secret");
    };

    repeat(action, until);
}

1 回実行して、同じパスワードがどれだけ奇妙に選択されるかを確認します。

2015-01-09 15:41:33.350 [スレッド 1] [情報] najjcPracticeQuestionsCh6Test - 受信したパスワード: secretPassword。2015-01-09 15:41:34.371 [スレッド 3] [情報] najjcPracticeQuestionsCh6Test - 受信したパスワード: secretPassword。2015-01-09 15:41:35.442 [スレッド 5] [情報] najjcPracticeQuestionsCh6Test - 受信したパスワード: secretPassword。2015-01-09 15:41:36.443 [スレッド 7] [情報] najjcPracticeQuestionsCh6Test - 受信したパスワード: secretPassword。2015-01-09 15:41:37.451 [スレッド 9] [情報] najjcPracticeQuestionsCh6Test - 受信したパスワード: secretPassword。

4

2 に答える 2

0

バグを見つけました。私が作成したサプライヤは、毎回同じ値を返していました。以下が修正後のコードです。ただし、1 つ質問があります。コンパイラがキャストを強制するのはなぜですか。

public static <T> CompletableFuture<T> repeat(final Supplier<T> action,
        final Predicate<T> until) {
    final CompletableFuture<T> futureAction = supplyAsync(action);

    @SuppressWarnings("unchecked")
    CompletableFuture<T> future = (CompletableFuture<T>) futureAction
        .thenApplyAsync(until::test).thenApply(
            isMatchFound -> isMatchFound ? futureAction : repeat(action, until));

    future.join();

    return future;

}
于 2015-01-09T22:53:05.880 に答える