函数式编程_类型拆装及重载解析
共 2156字,需浏览 5分钟
·
2022-04-01 21:04
朝臣待漏五更寒,
铁甲将军夜渡关。
山寺日高僧未起,
看来名利不如闲。
一首定场消声去,醒木拍桌开书来。各位看官,别来无恙,今儿个我们聊一番函数式编程的类库。
现如今jdk8,在各大公司可谓大行其道,对比前一代的code套路,jdk8的惰性求值、及早求值和内部迭代等一系列小操作可说是无往不胜,再加之引入接口静态方法、默认方法等等新特性,还有来自外界铺天盖地的职位投递要求,晦涩却有生动地的入职相邀,也难怪一众公众号竞相投递推送花样繁多却又内容高度统一地培训套餐广告及软文,话虽如此,有道是人各有志,老韭新韭皆是道友,入相飞天皆为修炼。值得一说的是,基于安全和开发舒适感考虑,雷记推荐尝试使用open jdk。
书归正传,让我们来探一番函数式类库地究竟。在雷记很久之前地帖子中,对于函数式地流做了一些简单的介绍,还有一些基于lambda和stream地使用的例子,让我们继续沿着这个思路搞下去。
要怎样在代码中使用lambda表达式?
由于lambda表达式函数接口的类型可以内部推导,因此在调用角度看来,调用lambda表达式和调用普通的接口方法没有区别。让我们看一个日常处理中十分常见的场景:
公司分派了一个新的项目下来,要处理大数据量的日志,在编码时日志框架中要设置类似void debug(String message)的方法,在判断上下文日志级别为debug时,要打印对应日志级别的日志。那么这时就会出现一个问题,要在各处判断日志级别是否为debug级别,频繁地计算判断会影响系统性能,海量的数据写入也会导致系统io占用率被打到很高。
面对这个情况,要拆分一下问题,首先日志等级判断的频繁性,其次是海量日志的io写,针对这两个问题,第一个可以采用lambda+判定开关降低性能开销,第二个可以采用基于epoll原型的nio方式,第二个问题展开讲在这里会有跑题的嫌疑,所以暂且不表。关于第一个问题,具体处理:
·重写logger类的debug方法:
public void debug(Supplier
if(isDebugEnaled()){
debug(message.get());
}
}
·日志判定采用lambda参数:
Logger log = new Logger();
log.debug(() -> "xxxx");
这里对于Supplier
@FunctionalInterface
public interface Supplier
/**
* Gets a result.
*
* @return a result
*/
T get();
}
函数式中对于基本类型、装箱类型的拆装箱处理
在java中有时我们想要一个包含整数型值的List
为了减小这类的性能开销,java8中stream对于整型、长整型、双浮点数进行了特殊处理,stream方法中命名带有to或以类型名开头的方法即是,因为经过了改善和优化,所以要尽可能多的使用这类函数,此外它还有很多额外的方法,可以避免我们重复造轮子实现一些通用且容易处bug的方法。
重载解析
java通过不同方法签名实现重载,这对于stream推断类型时会带来问题,导致推断出很多种类型,所以javac会挑出最具体的类型,对此有一个默认的规则:
·只有一个可能的目标类型,由相应函数接口的参数类型推到;
·有多个可能的目标类型,由最具体的类型推导得出;
·有多个可能的目标类型且最具体的类型不明确,需要人为指定类型;
@FunctionalInterface
为提高stream对象可操作性而引入的各类接口,都需要lambda表达式恶意实现它们,这类接口存在的意义是将代码块作为数据打包起来,这正是通过@FunctionalInterface做到的,@FunctionalInterface会强制javac检查一个接口是否符合函数接口标准,如果这个注释加到枚举类、类或另一个注释或接口包含不止一个抽象方法,在javac层面就会报错,使用它在重构代码时能很快发现问题。
结语
最近这段时间因为家庭和公司琐事,导致更新变慢,承蒙各位错爱,惶恐惶恐。后面地更新里,雷记打算尝试加一些vue的前端内容,进而最终过渡到小程序和app制作上,目前是这么打算。如果各位看官有更好的想法,欢迎私信雷记交流,那么今天的更新就是这样,愿诸位,酒色财气君莫占,招财进宝,日进斗金~