Конвертировать Runnable в поставщика - PullRequest
0 голосов
/ 10 февраля 2019

Как можно Runnable преобразовать в Supplier?

public <T> T useSupplier(Supplier<T> supplier) {
    // Does something with supplier and returns supplied value
    ...
    return value;
}

public void useRunnable(Runnable runnable) {
    // Somehow convert runnable to Supplier
    ...
    useSupplier(supplier);
}

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


Редактировать: Чтобы уточнить, метод useSupplier не имеетвзаимодействовать с предоставленным значением, оно просто возвращает его.Функциональность useSupplier заключается в получении значения от поставщика в некотором контексте, в моем случае он ловит (специфический) RuntimeException s, создает новое исключение с ним как причину и выдает его:

public <T> T useSupplier(Supplier<T> supplier) {
    try {
        return supplier.get();
    }
    catch (RuntimeException runtimeException) {
        throw new MyException("Supplier threw exception", runtimeException);
    }
}

Следующие решения не работают (в Java 8):

useSupplier(runnable);
useSupplier(runnable::run);
useSupplier((Supplier<Void>) runnable::run);

Одно из решений, которое я мог бы предложить, - это создать новый Supplier, который возвращает произвольныйзначение:

useSupplier(() -> {
    runnable.run();
    return null;
});

Есть ли меньшее решение?

Редактировать: Как отметил Хольгер в комментариях, использование runnable::run также создаст новые экземпляры лямбда-выражений, так как это состояние с состоянием, см.также этот ответ .

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Глядя на ваш дизайн, вы можете просто искать Consumer, который принимает тип и просто обрабатывает (потребляет) его без возврата значения и может использоваться также для адаптации выполняемого объекта вместо Supplier, которыйс другой стороны, ожидается, что он вернет (поставляет) значение после обработки.

Вы можете использовать что-то вроде:

private static <T> void useConsumer(Consumer<T> consumer, T val) {
    // Does something with supplier and returns supplied value
    consumer.accept(val);
}

public static <T> void useRunnable(Runnable runnable) {
    useConsumer(Runnable::run, runnable);
}

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

public static void useRunnable(Runnable runnable) {
    useSupplier(() -> runnable); // the useSupplier returns the 'runnable' when this method is called
}

Как уже упоминалось в комментариях, теперь, когда вы вызываете useRunnable, useSupplier будет возвращать тот же runnable, но метод useRunnableснова void и, следовательно, полностью игнорируется.

0 голосов
/ 10 февраля 2019

В вашем случае вы не можете избежать создания нового объекта.Даже если где-то есть метод, который преобразует Runnable в поставщика, он создаст там объект.Таким образом, ваше решение действительно, вы не найдете ничего лучшего.

Обратите внимание на то, что поставщик должен предоставить значения, а Runnable просто представляет действие.Они используются для разных целей.Таким образом, ваша потребность в преобразовании Runnable в поставщика может быть результатом проблемы проектирования.

...