Потребитель вложить попробуй поймать логику не получится - PullRequest
0 голосов
/ 07 сентября 2018

Я выполняю рефакторинг некоего устаревшего кода и сталкиваюсь с этой функцией:

private static void parseOptionalValues(Product product, Input source) {
    try {
        product.setProductType(...some operation with source...);
    } catch (IllegalArgumentException ignored) {}
    try {
        product.setMaterial(...some operation with source...);
    } catch (IllegalArgumentException ignored) {}
    try {
        product.setUnitPricingBaseMeasure(...some operation with source...);
    } catch (IllegalArgumentException ignored) {}
    try {
        product.setUnitPricingMeasure(...some operation with source...);
    } catch(IllegalArgumentException ignored){}
}

Мой здравый смысл говорит мне, что для того, чтобы придерживаться принципа «Не повторяйся сам», я должен обернуть эту логику «попробуй и поймай», поэтому я ввел это изменение:

private static void parseOptionalValues(Product product, Input source) {
    setOptionalParameter(...some operation with source..., product::setProductType);
    setOptionalParameter(...some operation with source..., product::setMaterial);
    setOptionalParameter(...some operation with source..., product::setUnitPricingBaseMeasure);
    setOptionalParameter(...some operation with source..., product::setUnitPricingMeasure);
}

private static <T> void setOptionalParameter(T value, Consumer<T> consumer) {
    try {
        consumer.accept(value);
    } catch (IllegalArgumentException ignored) {}
}

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

Есть идеи, как решить эту проблему с помощью логики try-catch в одном месте?

1 Ответ

0 голосов
/ 07 сентября 2018

Я думаю, что проблема может заключаться в том, что исключение выдается кодом, который получает аргументы для передачи сеттерам. Таким образом, одним из возможных подходов было бы сделать эту часть кода ленивой с помощью Supplier, а затем вызвать .get() для Supplier внутри блока try/catch (а также вызвать Consumer):

private static <T> void setOptionalParameter(
        Supplier<? extends T> supplier, 
        Consumer<? super T> consumer) {

    try {
        consumer.accept(supplier.get());
    } catch (IllegalArgumentException ignored) {
    }
}

Вы можете вызвать этот метод следующим образом:

setOptionalParameter(() -> ...some operation with source..., product::setProductType);

Обратите внимание, что я улучшил сигнатуру вашего метода, так что теперь он принимает более широкий диапазон общих подтипов и супертипов для Supplier и Consumer соответственно.


РЕДАКТИРОВАТЬ: Согласно комментариям, описанный выше подход может быть недостаточно гибким, т. Е. Если метод принимает более одного аргумента и т. Д. В этом случае было бы лучше использовать Runnable экземпляр:

private static void setOptionalParameter(Runnable action) {

    try {
        action.run();
    } catch (IllegalArgumentException ignored) {
    }
}

И вызов теперь стал бы:

setOptionalParameter(() -> {
    ProductType productType = ...some operation with source...;
    Material material = ...some operation with source...;

    product.doSomethingWith2Args(productType, material);
});
...