如何用好函数式接口|Java开发实践
开口
JDK8 被称为 Lambda。很多人会用,比如Stream流,但是简单好用,比如调用集合的Stream API,但是不会定义自己的函数接口或者API。今天,我们通过几个案例来改进Java中函数编程的使用。
案例演示
功能接口说明
界面
输入参数
返回类型
解释
一元运算符
吨
吨
具有相同输入和输出类型的一元函数
谓词
吨
布尔值
断言
消费者
吨
/
消费一个数据,只有输入,没有输出
函数<T,R>
吨
R
输入 T 返回 R,带有输入和输出
供应商
/
吨
提供一个数据,没有输入,只有输出
双函数<T,U,R>
(T,U)
R
两个输入参数
双谓词<L, R>
(左,右)
布尔值
两个输入参数
BiConsumer<T, U>
(T,U)
空白
两个输入参数
二元运算符
(T,T)
吨
具有相同输入和输出类型的二进制函数
案例一
函数<整数, 整数> times2 u003d e -> e * 2;
函数<整数, 整数> 平方 u003d e -> e * e;
// 先执行参数再执行调用者
/*
* 1. 4 * 4 u003d 16 16 * 2 u003d 32
*/
System.out.println("结果:" + times2.compose(squared).apply(4)); // 32
/*
* 先执行调用者:4 * 2 u003d 8,再执行当时传入的函数 8 * 8 u003d 64
*/
System.out.println("结果:" + times2.andThen(squared).apply(4)); // 64
和Then这两个方法是在Function外面执行之后调用的,compose表示Function在外面执行之前被调用。
案例二
@测试
公共无效 test2(){
// 添加三个数字
函数<整数, 函数<整数, IntFunction<整数>>> addfun3 u003d x -> y -> z -> x + y + z ;
// 添加 7 个数字
函数<整数,
函数<整数,
函数<整数,
函数<整数,
函数<整数,
函数<整数, IntFunction<整数>>>>>>>
addfun7 u003d x -> y -> z -> a -> c -> b -> d -> x + y + z + a + c + b + d;
// 1+2+3
整数和 u003d addfun3.apply(1).apply(2).apply(3);
System.out.println(sum);
}
这样就可以实现链式编程的累积效应
案例3
@SafeVarargs
私有静态 <R> 函数<R, R> combineFunctions(Function<R, R>...函数) {
返回 Arrays.stream(函数)
.reduce(函数::然后)
.orElseThrow(() -> new IllegalArgumentException("没有要组合的函数"));
}
@测试
公共无效 test3() {
函数<整数, 整数> addfun2 u003d x -> x * x;
最终整数应用 u003d combineFunctions(addfun2, addfun2).apply(2);
System.out.println(应用);
字符串 str u003d "1,2,3,4,5,6";
函数<Object, Object> splitByComma u003d s -> ((String) s).split(",");
Function<Object, Object> convertToInt u003d tokens -> Stream.of((String[]) tokens).map(Integer::valueOf).toArray(Integer[]::new);
Function<Object, Object> find Max u003d in -> Stream.of((Integer[]) int).max(Integer::compare).get();
Integer max u003d (Integer) combineFunctions(splitByComma, convertToInt, findMax).apply(str);
System.out.println(max);
}
如果想要有一个方法接受变长函数参数,可以使用Descriptor,其中泛型<R,R>代表输入和输入类型。泛型用于更高的兼容性
案例4
@测试
公共无效 test4(){
函数<整数, 整数> addfun2 u003d x -> x * x;
final Calculator<Integer, Integer> 计算器 u003d new Calculator<>(2);
最终整数整数 u003d 计算器.combineFunctions(addfun2, addfun2);
System.out.println(整数);
}
公共类计算器<R,T> {
// 要操作的属性
私有对象输入;
公共计算器(对象输入){
this.input u003d 输入;
}
// 可以这样定义对象本身的行为
@SuppressWarnings("未选中")
@SafeVarargs
公共最终 R combineFunctions(Function<T, T>... 函数) {
返回 (R) Arrays.stream(函数)
.reduce(函数::然后)
.orElseThrow(() -> new IllegalArgumentException("没有要组合的函数"))
.apply((T)输入);
}
}
领域开发模式已经或多或少地被听到和理解。除了自己的属性之外,对象还可以有自己的行为。对象的行为方法也可以由函数式编程范式定义。
案例5
// Biconsumer < T, Integer > 两个输入参数 T, Integer
公共静态 <T> Consumer<T> consumerWithIndex(BiConsumer<T, Integer> consumer) {
类对象 {
诠释我;
}
// 它只会被调用一次。原因取决于Java lang.Iterable#forEach
对象 obj u003d 新对象();
// 消费者函数返回
返回 t -> {
int 索引 u003d obj.i++;
// 执行系统。 Println("list [" + index + "] u003d" + item ") 消费指定泛型类型的数据。
消费者.accept(t, index);
};
}
@测试
公共无效 test5(){
val list u003d Arrays.asList("Hi", "I", "am", "Henry.Yao");
// 2 个元素为一组
val 分区 u003d Lists.partition(list, 2);
partition.forEach(LambdaUtils.consumerWithIndex((项目,索引)-> {
System.out.println("list[" + index + "]u003d" + item);
}));
}
Java 8 的 forEach() 循环对象时,无法获取对象索引下标。在这种情况下,您可以声明一个函数方法来执行此操作。最终的写法类似于Scala和js的forEach语法,非常好用!
java.lang.Iterable#forEach
// action: 是一个消费者函数
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(动作);
for (T t : 这个) {
/* 这里会循环调用Consumer函数,consumerWithIndex返回的Consumer函数内容为
t -> {
int 索引 u003d obj.i++;
消费者.accept(t, index);
}
因此,Obj obj u003d new Obj() 只会被调用一次,所以你不必担心如果在 new Obj 期间 i 没有被重置为 0,它就不会发生
*/
消费者.accept(t, index);
}
action.accept(t);
}
}
如果觉得文章对你有帮助,请点赞、评论、收藏。您的支持是我最大的动力!!!
最后小编在学习过程中整理了一些学习资料,可以分享给Java工程师朋友们互相交流学习,如有需要可以加入我的学习交流群323432957免费获取Java架构学习资料(包括高可用、高并发、高性能与分布式、Jvm性能调优、Spring源码、MyBatis、Netty、Redis、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点的架构资料。 )
作者:dingyu002
来源:dinyu002
版权归作者所有。如需商业转载,请联系作者授权。非商业转载请注明出处。
更多推荐
所有评论(0)