Java 8 Композиция, карринг сокращений - PullRequest
2 голосов
/ 30 апреля 2019

У меня есть поток BusinessObject s, мне нужно установить значение для каждого объекта, я хочу использовать Stream.map, но map принимает Function<T,R>, и у меня есть целевой объект, значение дискриминатора,и новое значение.setNewValueInBusinessObjectExample показывает, что я хочу сделать, а setNewValueInBusinessObjectWithFun - это то, с чем мне нужна помощь.

Согласен!Я могу просто использовать setNewValueInBusinessObjectExample на карте, но я хочу посмотреть, как выглядит функциональный стиль.Спасибо

class BusinessObject {
    String firstField;
    String secondField;
}

class SomeDiscriminator {
    String value;
}

BusinessObject setNewValueInBusinessObjectExample(BusinessObject businessObject, 
     SomeDiscriminator discriminator, String newValue) {

    if(discriminator.value.equals("firstField")) {
        businessObject.firstField = newValue;
    } else {//secondField
        businessObject.secondField = newValue;
    }

    return businessObject;
}

Function<BusinessObject, Function<SomeDiscriminator, Function<String, BusinessObject>>> 
       setNewValueInBusinessObjectWithFun = {
    /* todo: using nested Function<T,R> */
}

Ответы [ 3 ]

3 голосов
/ 30 апреля 2019

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

Я также заметил, что весь поток использует три параметра, то же самое, что ваш setNewValueInBusinessObjectExample.Таким образом, переместите тело метода в самый внутренний анонимный класс.

Function<BusinessObject, Function<SomeDiscriminator, Function<String, BusinessObject>>> setNewValueInBusinessObjectWithFun =
    new Function<BusinessObject, Function<SomeDiscriminator, Function<String, BusinessObject>>>() {
        @Override
        public Function<SomeDiscriminator, Function<String, BusinessObject>> apply(final BusinessObject businessObject) {
            return new Function<SomeDiscriminator, Function<String, BusinessObject>>() {
                @Override
                public Function<String, BusinessObject> apply(final SomeDiscriminator someDiscriminator) {
                    return new Function<String, BusinessObject>() {
                        @Override
                        public BusinessObject apply(final String newValue) {
                            if (someDiscriminator.value.equals("firstField")) {
                                businessObject.firstField = newValue;
                            } else {//secondField
                                businessObject.secondField = newValue;
                            }
                            return businessObject;
                        }
                    };
                }
            };
        }
    };

Теперь упакуйте все это в лямбда-выражения и посмотрите, что произойдет:

Function<BusinessObject, Function<SomeDiscriminator, Function<String, BusinessObject>>> setNewValueInBusinessObjectWithFun = 
    businessObject -> someDiscriminator -> newValue -> {
        if (someDiscriminator.value.equals("firstField")) {
            businessObject.firstField = newValue;
        } else {//secondField
            businessObject.secondField = newValue;
        }
        return businessObject;
    };

Для ясности,правильно называйте переменные внутри лямбда-выражения, иначе вы не сможете хорошо с ними работать.Использование довольно простое (для краткости я переместил сеттеры в конструктор:

BusinessObject businessObject = new BusinessObject("oldValue");
setNewValueInBusinessObjectWithFun
    .apply(businessObject)                                  // apply to an object
    .apply(new SomeDiscriminator("firstField"))             // finds its field
    .apply("newValue");                                     // sets a new value

Однако я рекомендую вам определить пользовательский @FunctionalInterface с более простым определением ...

@FunctionalInterface
interface MyFunction<T, R, U> {
    T apply(T t, R r, U u);
}

... и использование ...

MyFunction<BusinessObject, SomeDiscriminator, String> myFunction = 
    (businessObject, someDiscriminator, newValue) -> {
        if (someDiscriminator.value.equals("firstField")) {
            businessObject.firstField = newValue;
        } else {
            businessObject.secondField = newValue;
        }
        return businessObject;
    };

BusinessObject businessObject = new BusinessObject("oldValue");
myFunction.apply(businessObject, new SomeDiscriminator("firstField"), "newValue");
0 голосов
/ 30 апреля 2019

Это не должно быть сложным.Если у вас есть Stream<BusinessObject>, то ни SomeDiscriminator, ни значение String не являются элементами потока.

Так что Function<BusinessObject, BusinessObject> необходимо передать map:

Stream<BusinessObject> businessObjectStream = null;
SomeDiscriminator discriminator = null; String newValue = "";

Function<BusinessObject, BusinessObject> mapper = businessObject -> {
    if (discriminator.value.equals("firstField")) {
        businessObject.firstField = newValue;
    } else {//secondField
        businessObject.secondField = newValue;
    }

    return businessObject;
};

Вызывается с помощью:

businessObjectStream.map(mapper);

Даже если бы логика discriminator.value.equals("firstField") зависела от динамических значений в объекте потока, вам, возможно, понадобилось бы где-то Predicate<...>, но на самом деле даже нефункция высшего порядка, которая возвращает функцию динамически.

0 голосов
/ 30 апреля 2019

Не совсем уверен, что получаю то, что вам может понадобиться, но что-то вроде этого?

static Function<BusinessObject, Function<SomeDiscriminator, Function<String, BusinessObject>>>
    setNewValueInBusinessObjectWithFun =
    x -> y -> z -> {
        if ("firstfield".equals(y.value)) {
            x.firstField = z;
        } else {
            x.secondField = z;
        }
        return x;
    };

И использование будет:

    BusinessObject bo = new BusinessObject();
    bo.firstField = "test";

    SomeDiscriminator sd = new SomeDiscriminator();
    sd.value = "firstField";
    bo = setNewValueInBusinessObjectWithFun.apply(bo).apply(sd).apply("value");

    System.out.println(bo.firstField);
...