Я изучаю использование,
java.util.function.Function
Я написал код, который использует функцию java для добавления 4 к себе,
код выглядит следующим образом,
public class Test01 {
public static void main(String[] args) {
Function<Integer,Integer> addFunction = new Function<Integer,Integer>() {
private int total = 0;
public Integer apply(Integer value) {
this.total += value;
return this.total;
}
};
int finalTotal = addFunction.andThen(addFunction)
.andThen(addFunction)
.andThen(addFunction)
.apply(4);
System.out.println(finalTotal);
}
}
Когда я запускаю приведенный выше код, я получаю вывод
32
Как я могу добиться того, что я сделал в javaScript, а именно:
var fn19 = function(){
var addNum = function(num){
var fn = function(num2){
fn.sum += num2;
return fn;
};
fn.sum = num;
return fn;
};
print("addNum(3)(4)(3)(10) ==> "+addNum(3)(4)(3)(10).sum);
};
fn19();
Вывод приведенного выше кода
addNum(3)(4)(3)(10) ==> 20
Могу ли я иметь такой же вызов функции Java, где я могу передать столько числовых аргументов, и addFunction добавит эти числа.
Как это связано с RxJava?
Вы не можете точно сделать это в Java, то, что вы ищете, это уменьшение поток значений.
Другими словами: «настоящее» функциональное решение здесь не в том, чтобы вызывать один метод с несколькими аргументами. У вас скорее есть значения в каком-то списке, а затем вы определяете функцию, которая «накапливается» по содержимому этого списка, применяя функцию к элементам.
См. здесь для некоторых примеров.
Техника, которую вы описываете в мире JavaScript, использует замыкание.
Это приятный побочный эффект того, что функции в JavaScript являются гражданами первого класса. Это способ связать функции с данными во внешней области видимости, а затем передать эту связь без потери внутреннего контекста. Наиболее распространенным/простым применением является кэширование (официальное название — мемоизация).
Вам понадобятся функции (методы) в Java, чтобы они были первоклассными, но это было бы избыточно, поскольку классы по дизайну представляют собой сущность, которая связывает данные и методы, что делает всю концепцию закрытия в этом контексте избыточной.
Примером, максимально приближенным к вашему коду JavaScript, будет
class QuestionableConstruct {
int sum;
QuestionableConstruct add(int num2) {
sum += num2;
return this;
}
}
Runnable fn19 = () -> {
IntFunction<QuestionableConstruct> addNum = num -> {
QuestionableConstruct fn = new QuestionableConstruct();
fn.sum = num;
return fn;
};
System.out.println("addNum(3)(4)(3)(10)==> "+addNum.apply(3).add(4).add(3).add(10).sum);
};
fn19.run();
Более похожее на Java решение было бы
interface Add {
int sum();
default Add add(int num) {
int sum = sum() + num;
return () -> sum;
}
static Add num(int num) {
return () -> num;
}
}
можно использовать как
System.out.println("addNum(3)(4)(3)(10) ==> "+Add.num(3).add(4).add(3).add(10).sum());
В отличие от конструкции JavaScript, здесь используются настоящие неизменяемые функции. Рассмотреть возможность
Add a = Add.num(1).add(2).add(3);
System.out.println("1+2+3+4+5 = "+a.add(4).add(5).sum());
System.out.println("1+2+3+10+20 = "+a.add(10).add(20).sum());
который работает плавно без помех.
Но, конечно, если вы просто хотите суммировать переменное количество элементов, используйте
System.out.println("addNum(3)(4)(3)(10) ==> "+IntStream.of(3, 4, 3, 10).sum());
или если вам нужен изменяемый аккумулятор, используйте
System.out.println("addNum(3)(4)(3)(10) ==> "+
IntStream.builder().add(3).add(4).add(3).add(10).build().sum());
что позволяет держать конструктор и передавать его.
Не очень легко, так как Java — типизированный язык. Чтобы получить доступ к полю, вам нужно определить тип, который реализует
Function<...>
, но дает вам доступ к чему-то другому, кроме контракта этого интерфейса. Кроме того, вы, похоже, используете эквивалентFunction<Integer,Function<Integer>>
в своем коде Javascript, а неFunctyon<Integer,Integer>
.