继续java8新亮点的源码之路 , functional interface是一个跳不过的坎 , 它与lambda的结合使用非常普遍 。**java.util.function**包对于每一个java工程师来说是必备技能 , 也是最基础的能力 , 一定要掌握 。
文章插图
函数编程的最直接的表现在于将函数作为数据自由传递 , 结合泛型推导能力使代码表达能力获得飞一般的提升 。同时Lambda表达式让你能够将函数作为方法参数或者将代码作为数据对待 , 让你发现“行级代码”优美 。
java8引入新的注解 , @FunctionalInterface函数式注解@FunctionalInterface添加在一个接口上 , 主要是编译器检查提示作用 。
1. 注解的作用是检测自定义functional接口是否符合要求 , 编译器会有错误提示;
2. 一个接口符合functional的要求 , 不加这个注解也可以正常使用 , **建议都加上**;
3. 有且只能有一个抽象方法但可以有多个非抽象方法 , 简单说就是接口里面default和static的方法是可以有多个的 , 其他的方法只能有一个 。
lambda表达式写法及注意点> 格式:`( parameters ) -> { statements; }` 。
1. 不需要声明参数类型 , 编译器可以识别参数值;
2. 单个参数和语句下 , 圆括弧和大括弧可以省略;
3. 表达式是一个闭包 , 定义了行内执行的方法类型接口;
4. 只能引用标记了final的外层局部变量 , 不能在表达式内部修改定义在域外的局部变量 , 否则会编译错误;
5. 表达式当中不允许声明一个与局部变量同名的参数或者局部变量;
写法示例:
@FunctionalInterfacepublic interface IPerson { String say(String input); //void stand(); 只能有一个抽象方法 , 不然编译无法默认识别调用 static void run(String xx){ PrintUtil.printTest("IPerson run : " + xx); } static void walk(){ PrintUtil.printTest("IPerson walk"); } default void eat(int a, int b){ PrintUtil.printTest("IPerson eat : " + a + " - " + b); }}//当你这种写法是编译器会提示你用lambdaIPerson person = new IPerson() { @Override public String say(String input) { return "My said is " + input; }};PrintUtil.printTest(person.say("i love china."));//lambda写法IPerson person2 = a -> "My said is " +a;PrintUtil.printTest(person2.say("i love china."));//结果是一样的 , My said is i love china.function包中重要接口源码分析
文章插图
Consumer , 接收一个输入参数T类型并不没有返回值;andThen看源码可以知道是添加一个其后执行的Consumer对象 。
这个接口很简单不需要什么解释 , 看源码一眼OK 。
@FunctionalInterfacepublic interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }}Function , 接收一个T类型参数 , 返回一个R类型的结果 。需要注意的是compose\andThen的传入参数和范围参数规则不同 , 这里的参数类型稍有不慎就会出错 , 复杂的链路里面排查bug是非常麻烦的事 。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
//生成了function的参数类型同before一样
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//新生成的function的返回值类型要after一样
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
//
static <T> Function<T, T> identity() {
return t -> t;
}
}
测试用例:
Function<Integer,String> function = a -> "== " + a;PrintUtil.printTest(function.apply(101));Function<String,Boolean> function1 = c -> c.length()>2;PrintUtil.printTest(function1.apply("1a"));PrintUtil.printTest(function.andThen(function1).apply(111));//andThen类似consumer , 是前一个function执行后结果作为参数传新生成的function执行 , 结构:trueFunction<Integer,Integer> function2 = c -> c*c;//compose和andThen正好逻辑相反 , 传入的参数function先执行后范围结果作为参数传给新生成的function执行PrintUtil.printTest(function.compose(function2).apply(2));//先执行function2 , 返回结果作为参数再执行function , 结果:== 4PrintUtil.printTest(function.compose(function2).andThen(function1).apply(2));//先执行function2 , 其次执行funciton , 最后执行function1 , 结果:truePrintUtil.printTest(function2.compose(function2).apply(2));//先执行第二个function2 , 返回结果作为参数再执行第一个function2 , 结果:16//递归的实现又多了种办法Function<String,String> function3 = Function.identity();//static方法PrintUtil.printTest(function3.apply("hello"));//identity定义了一个只返回输入参数的function,结果:hello
秒懂生活扩展阅读
- 形容树木苍翠茂盛的词语是什么
- 关于冬天的景物描写
- PDF文档的显示比例如何设置
- 蜘蛛会飞吗蜘蛛是怎样结网的
- 余额宝最安全的使用方法 支付宝的余额宝怎么使用
- 天猫直播和淘宝直播的区别是什么?哪个好?
- 淘宝密保设置的方法是什么?
- 网上开店的货源渠道有哪些?选货要注意什么?
- 天然气的含硫量是多少
- 高温和加热的区别是什么