网站首页 > java教程 正文
继续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. 表达式当中不允许声明一个与局部变量同名的参数或者局部变量;
写法示例:
@FunctionalInterface public 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); } } //当你这种写法是编译器会提示你用lambda IPerson 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。
@FunctionalInterface public 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执行,结构:true Function<Integer,Integer> function2 = c -> c*c; //compose和andThen正好逻辑相反,传入的参数function先执行后范围结果作为参数传给新生成的function执行 PrintUtil.printTest(function.compose(function2).apply(2)); //先执行function2,返回结果作为参数再执行function,结果:== 4 PrintUtil.printTest(function.compose(function2).andThen(function1).apply(2)); //先执行function2,其次执行funciton,最后执行function1,结果:true PrintUtil.printTest(function2.compose(function2).apply(2)); //先执行第二个function2,返回结果作为参数再执行第一个function2,结果:16 //递归的实现又多了种办法 Function<String,String> function3 = Function.identity();//static方法 PrintUtil.printTest(function3.apply("hello")); //identity定义了一个只返回输入参数的function,结果:hello
Predicate,是一个条件判断接口,接收一个T参数范围boolean值,默认抽象方法test(t);and\or\negate分别对应逻辑与、或、非操作,isEqual。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
//逻辑与
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//获取该对象否定的Predicate,相当于逆转boolean
default Predicate<T> negate() {
return (t) -> !test(t);
}
//逻辑或
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
//生成一个判断对象是否相等的Predicate
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
测试用例:
Predicate<ICar> carHas4Wheel = a -> a.getWheelCount() > 3;
ICar weilai = new WeiLaiCar(3);
PrintUtil.printTest(carHas4Wheel.test(weilai));
//false
PrintUtil.printTest(carHas4Wheel.negate().test(weilai));
//true
PrintUtil.printTest(carHas4Wheel.and(b -> b.getWheelCount()>2).test(weilai));
//false
PrintUtil.printTest(carHas4Wheel.and(b -> b.getWheelCount()>2).test(new WeiLaiCar(4)));
//true
PrintUtil.printTest(carHas4Wheel.or(b -> b.getWheelCount()>2).test(new WeiLaiCar(3)));
//true
PrintUtil.printTest(Predicate.isEqual(weilai).test(weilai));
//true
PrintUtil.printTest(Predicate.isEqual(weilai).test(new WeiLaiCar(3)));
//false
Supplier,是一个只有返回没有参数的接口,只有一个方法get。
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * @return a result */ T get(); }
测试用例:
Supplier<Integer> supplier = () -> 1 ; PrintUtil.printTest(supplier.get()); //1 Supplier<ICar> carSupplier = () -> new WeiLaiCar(5) ; PrintUtil.printTest(carSupplier.get() + " : " + carSupplier.get().getWheelCount()); //com.ts.util.optional.WeiLaiCar@32a1bec0 : 5
Consumer<T> Predicate<T> Supplier<T> Function<T, R> BiFunction<T, U, V>
这里的T U R V并没有特别的定义只是一种约定,就像驼峰命名和泛型中K V E一样。
分享连接
除了介绍的几种函数式接口外,java8在这几个基础上封装了很多的延伸接口,如BiConsumer\ DoubleConsumer\ IntConsumer\ LongConsumer\ ObjIntConsumer等。平时写代码时注意积累,闲的时候多去看看API,慢慢的就掌握了。
Lambda和Functional的结合很大一点就是代码简洁了,看着非常的赏心悦目。JAVA一个纯面向对象的语言,在行级代码上一直是非常的简洁易于调试,而这两个新特性的出现让行级代码的复杂度急剧提升。
相关用例代码已托管Github:https://github.com/owen-jia/play-java-sample.git 。
推荐关注
作者:Owen Jia
推荐关注他的博客:https://blog.shareworld.vip
猜你喜欢
- 2024-09-27 Java 8新特性探究(一)通往lambda之路_语法篇
- 2024-09-27 Java 8新特性:集合迭代、并行处理及函数式接口
- 2024-09-27 Java8的新特性(四)(java8新特性分组)
- 2024-09-27 Java 8之后的那些新特性(一):局部变量var
- 2024-09-27 java8中一个极其强悍的新特性Stream(非常实用)
- 2024-09-27 Java 17 新特性已经确定,进入了发布倒计时
- 2024-09-27 跟上Java8–你忽略了的新特性(java8 64位)
- 2024-09-27 Java 8 新特性专栏,免费阅读(java8新特性optional用法)
- 2024-09-27 Java 8新特性详解与实例演示(java+8新特性详解与实例演示过程)
- 2024-09-27 Java 8 的这些特性,用起来真的很爽
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)