Java 8 перерыв для каждого с альтернативным действием - PullRequest
7 голосов
/ 16 января 2020

У меня есть следующий класс:

public class CloseableRepeater<R extends Closeable> {

    /**
     * Repeats the supplier until the stop condition becomes <code>true</code>.
     *
     * @param supplier The supplier to be repeated.
     * @param until  The stop condition.
     * @param times  The maximum repeat times.
     * @return The result.
     */
    public Optional<R> repeat(Supplier<R> supplier, Predicate<R> until, int times) {
        R r = null;
        for (int i = 0; i < times; i++) {
            r = supplier.get();
            if (until.test(r)) {
                break;
            } else {
                try {
                    r.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }
        return Optional.of(r);
    }

}

По сути, он повторяет действие до тех пор, пока условие не выполнено, и закрывает элементы, которые его не выполняют.


Мой вопрос

Есть ли возможность переписать метод repeat с помощью функционального программирования?


Я знаю, что код достаточно хорош, как есть, но Цель этого вопроса - улучшить мои навыки функционального программирования и найти его ограничения

Самое близкое, что у меня есть:

public Optional<R> repeat(Supplier<R> supplier, Predicate<R> until, int times) {
    return IntStream.range(0, times).mapToObj(i -> supplier.get()).filter(until).findFirst();
}

, но часть close отсутствует.

Ответы [ 2 ]

5 голосов
/ 16 января 2020

После комментария @ VinceEmigh, я думаю, что нашел решение:

   public Optional<R> functionalRepeat(Supplier<R> supplier, Predicate<R> until, int times) {
        return Stream.generate(supplier).limit(times).filter(until.or(t -> {
            try {
                t.close();
            } catch (IOException e) {
                // Ignore
            }
            return false;
        })).findFirst();
    }

Идея состоит в том, чтобы вызвать close во время фильтрации, связав предикат until с другим, который выполняет закрытие , используя тот факт, что речь идет о коротком замыкании логического ИЛИ.

Условие фильтрации истинно, если предикат until истинен, поэтому они логически эквивалентны.

Обновление

На самом деле, приведенный выше код не эквивалентен исходному, поскольку при отсутствии совпадения он создает пустой необязательный код, в то время как исходный код создает дополнительный, содержащий последний не элемент.

2 голосов
/ 16 января 2020

A l oop неплох и лучше подходит для этой конкретной проблемы c. Но вы можете немного его очистить:

public Optional<R> repeat(Supplier<R> supplier, Predicate<R> until, int times) {
    for(int i = 0; i < times; i++) {
        R r = supplier.get();
        if(until.test(r)) return Optional.of(r);
        try {
            r.close();
        } catch(IOException e) {
            // Ignore
        }
    }
    return Optional.empty();
}

Целью метода, безусловно, было возвращение пустого необязательного аргумента, когда совпадение не найдено (хотя закрытие null не должно поддерживаться и приводить к NullPointerException). Лучше, когда это обрабатывается потоком кода по своей сути вместо предварительной инициализации переменной с помощью null, что привело к ситуации, когда ваш исходный код не мог отличить результат null и никакого существующего элемента и даже хуже, может вернуть неправильный элемент.

Стоит рассмотреть возможность использования <R extends AutoCloseable> для повышения гибкости, вам нужно всего лишь изменить catch(IOException e) на catch(Exception e), пока существующие абоненты продолжают работать, но возможны и другие варианты использования. .

...