行为参数化&Lambda表达式

本文深入解析Lambda表达式在Java中的应用,包括其语法结构、如何作为函数式接口的实例,以及如何引用外部变量和方法。同时,介绍了不同场景下Lambda表达式的使用案例,如Predicate、Consumer和Function接口的应用,以及构造方法和静态方法的引用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表达式组成:

(parameters)->expression

(parameters)->{statements;},例如:

示例1:(String s)->s.length()

具有一个String类型的参数并返回一个int类型。Lambda没有return语句,因为已经隐含了return。

示例2:(Apple a)->a.getWeight()>150

有一个Apple类型的参数并返回一个boolean类型。

示例3:(int x,int y)->{

System.out.println(“result:”+i);

System.out.println(x+y);

}具有两个int类型的参数而没有返回值,Lambda表达式可以包含多行语句。

示例4:()->42

表达式没有参数,返回一个int类型。

示例5:(Apple a1,Apple a2)->

a1.getWeight().compareTo(a2.getWeight())

表达式具有两个Apple类型的参数,并返回一个int类型。

Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。(函数式接口指的是仅仅有一个方法的interface接口,这里表达的意思是Lambda可以作为接口的匿名内部类)

函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,我们将这种抽象方法叫做函数描述符。(意思就是interface中方法的参数类型、参数数量、返回值要跟Lambda表达式中的完全一致,想想也是,毕竟是要作为接口默认实现的,没办法)

Runnable r1 = ()->System.out.println
(“Hello World!”);

prcess(r1);

process(()->System.out.println(“Hello World!”));

由于Runnable是个接口且该接口只有一个方法,所以可以用Lambda来创建实例。

工具类

java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,该方法接受泛型T对象并返回一个boolean类型,该接口适用于涉及类型T的布尔表达式。(就是参数需要boolean值时可以用该接口,下面类似)

java.util.function.Consumer<T>定义一个accept抽象方法,接受泛型T的对象且没有返回void。

java.util.function.Function<T,R>定义一个叫做apply的方法,接受一个泛型T的对象并返回一个泛型R的对象。

Lambda引用外部变量

int port = 1337;

Runnable r = ()->System.out.println(port);

注意:局部变量必须是显式声明为final或事实上的final。

为什么会有这个限制?假如port变量在线程A中,Lambda则可能在线程B上,此时线程B去访问线程A的时候port可能已经不存在了,为了避免这种情况发生,线程B存有port变量的一份拷贝副本,既然是副本,那就存在着副本与原件的问题,采用final变量则能保证副本与原件的一致性。

方法引用

方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。基本思想就是如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。

使用方法引用时,目标引用放在分隔符::前面,方法名称放在::后面,例如:

(App a)->a.getW()等价于App::getW

(str,i)->str.substring(i)等价于String::substring

(String s)->System.out.println(s)等价于System.out::println

静态方法的引用

Lambda:

(args)->ClassName.staticMethod(args)

方法引用:

ClassName::staticMethod

实例方法的引用

①Lambda:

(arg,rest)->arg.instanceMethod(rest)

方法引用:arg是ClassName类型

ClassName::instanceMethod

②Lambda:(arg)->expr.instanceMethod(arg)

方法引用:

expr::instanceMethod

③注意:第一个与第二个区别在于第一个是调用参数的实例方法,第二个是调用外部变量的实例方法。

构造方法引用

用类名称和关键字new来创建一个应用:ClassName::new。

调用无参的构造方法

Supplier<App> c1=App::new;

App a1=c1.get();

通过::new来指向App的默认构造方法,然后通过Supplier的get方法来产生一个新的App。

调用一个参数的构造方法

java.util.function.Function<Integer,App> c1=App:new;

App a1=c1.apply(1);

由于java.util.function.Function<T,R>定义一个叫做apply的方法,接受一个泛型T的对象并返回一个泛型R的对象,也就是通过Function的apply来间接生成App对象。

调用两个参数的构造方法

java.util.function.BiFunction<String,Integer,App> c1=App:new;

App a1=c1.apply(“test”,10);

总结

静态方法调用为ClassName::staticMethod

构造方法调用为ClassName::new

假如某个ClassName的构造方法有N个参数的话,那就需要自己去创建一个与ClassName的构造方法的签名匹配的函数式接口,例如:App的构造方法是5个参数,可以这样:

public interface TFunction<T,U,V,App>{

App apply(T t,U u,V v);

}

(parameters)->expression中只要parameters数量、类型以及expression返回值与XX方法签名匹配就行,不在乎方法是哪个ClassName的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值