java 的function_java8新特性function和lambda深度解析

继续java8新亮点的源码之路,functional interface是一个跳不过的坎,它与lambda的结合使用非常普遍。java.util.function包对于每一个java工程师来说是必备技能,也是最基础的能力,一定要掌握。

60462ac1559b

head-icon

函数编程的最直接的表现在于将函数作为数据自由传递,结合泛型推导能力使代码表达能力获得飞一般的提升。同时Lambda表达式让你能够将函数作为方法参数或者将代码作为数据对待,让你发现“行级代码”优美。

java8引入新的注解,@FunctionalInterface

函数式注解@FunctionalInterface添加在一个接口上,主要是编译器检查提示作用。

注解的作用是检测自定义functional接口是否符合要求,编译器会有错误提示;

一个接口符合functional的要求,不加这个注解也可以正常使用,建议都加上;

有且只能有一个抽象方法但可以有多个非抽象方法,简单说就是接口里面default和static的方法是可以有多个的,其他的方法只能有一个。

lambda表达式写法及注意点

格式:

( parameters ) -> { statements; }

不需要声明参数类型,编译器可以识别参数值;

单个参数和语句下,圆括弧和大括弧可以省略;

表达式是一个闭包,定义了行内执行的方法类型接口;

只能引用标记了final的外层局部变量,不能在表达式内部修改定义在域外的局部变量,否则会编译错误;

表达式当中不允许声明一个与局部变量同名的参数或者局部变量;

写法示例:

@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包中重要接口源码分析

60462ac1559b

java8function

Consumer,接收一个输入参数T类型并不没有返回值;andThen看源码可以知道是添加一个其后执行的Consumer对象。

这个接口很简单不需要什么解释,看源码一眼OK。

@FunctionalInterface

public interface Consumer {

void accept(T t);

default Consumer 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 {

R apply(T t);

//生成了function的参数类型同before一样

default Function compose(Function super V, ? extends T> before) {

Objects.requireNonNull(before);

return (V v) -> apply(before.apply(v));

}

//新生成的function的返回值类型要after一样

default Function andThen(Function super R, ? extends V> after) {

Objects.requireNonNull(after);

return (T t) -> after.apply(apply(t));

}

//

static Function identity() {

return t -> t;

}

}

测试用例:

Function function = a -> "== " + a;

PrintUtil.printTest(function.apply(101));

Function function1 = c -> c.length()>2;

PrintUtil.printTest(function1.apply("1a"));

PrintUtil.printTest(function.andThen(function1).apply(111));

//andThen类似consumer,是前一个function执行后结果作为参数传新生成的function执行,结构:true

Function 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 function3 = Function.identity();//static方法

PrintUtil.printTest(function3.apply("hello"));

//identity定义了一个只返回输入参数的function,结果:hello

60462ac1559b

confuse

Predicate,是一个条件判断接口,接收一个T参数范围boolean值,默认抽象方法test(t);and\or\negate分别对应逻辑与、或、非操作,isEqual。

@FunctionalInterface

public interface Predicate {

boolean test(T t);

//逻辑与

default Predicate and(Predicate super T> other) {

Objects.requireNonNull(other);

return (t) -> test(t) && other.test(t);

}

//获取该对象否定的Predicate,相当于逆转boolean

default Predicate negate() {

return (t) -> !test(t);

}

//逻辑或

default Predicate or(Predicate super T> other) {

Objects.requireNonNull(other);

return (t) -> test(t) || other.test(t);

}

//生成一个判断对象是否相等的Predicate

static Predicate isEqual(Object targetRef) {

return (null == targetRef)

? Objects::isNull

: object -> targetRef.equals(object);

}

}

测试用例:

Predicate 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 {

/**

* Gets a result.

* @return a result

*/

T get();

}

测试用例:

Supplier supplier = () -> 1 ;

PrintUtil.printTest(supplier.get());

//1

Supplier carSupplier = () -> new WeiLaiCar(5) ;

PrintUtil.printTest(carSupplier.get() + " : " + carSupplier.get().getWheelCount());

//com.ts.util.optional.WeiLaiCar@32a1bec0 : 5

60462ac1559b

holdOn

Consumer Predicate Supplier Function BiFunction,这里的T U R V并没有特别的定义只是一种约定,就像驼峰命名和泛型中K V E一样。

分享连接

除了介绍的几种函数式接口外,java8在这几个基础上封装了很多的延伸接口,如BiConsumer\ DoubleConsumer\ IntConsumer\ LongConsumer\ ObjIntConsumer等。平时写代码时注意积累,闲的时候多去看看API,慢慢的就掌握了。

Lambda和Functional的结合很大一点就是代码简洁了,看着非常的赏心悦目。JAVA一个纯面向对象的语言,在行级代码上一直是非常的简洁易于调试,而这两个新特性的出现让行级代码的复杂度急剧提升。

相关用例代码已托管Github:play-java-sample。

推荐关注

作者:Owen Jia。

推荐关注他的博客:Owen Blog。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值