Java8如何使用Lambda表达式简化代码详解
系统环境:
- JavaJDK版本:1.8
参考地址:
- Java8Lambda表达式
- Jdk8新特性04方法引用与构造器引用
- Java8新特性:Lambda表达式之方法引用
一、Lambda表达式简介
1、什么是Lambda表达式
Lambda表达式是在JDK8中引入的一个新特性,可用于取代大部分的匿名内部类。使用Lambda表达式可以完成用少量的代码实现复杂的功能,极大的简化代码代码量和代码结构。同时,JDK中也增加了大量的内置函数式接口供我们使用,使得在使用Lambda表达式时更加简单、高效。
2、为什么需要Lambda表达式
谈起为什么需要Lambda表达式,那得从函数式编程开始说起。函数式编程可以简单说是一种编程规范,也就是如何编写程序的方法论。它属于结构化编程的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。函数式编程有很多优点,其中包括:
- 易于并发编程;
- 代码的热升级;
- 更方便的代码管理;
- 代码简洁,开发快速;
- 接近自然语言,易于理解;
函数式编程在C#、Python、JavaScript中都得到充分体现,在Java8版本中也得到了支持。最明显的就是对Lambda表达式的支持。很多种迹象表明未来编程语言将是逐渐融合各自的特性,而不是单纯的声明式语言函数编程语言。将来声明式编程语言借鉴函数编程思想,函数编程语言融合声明式编程特性,这几乎是一种必然趋势。
在Java中主要引入Lambda表达式的作用是对现有编码语义的优化,减少语法冗余。轻量级的将代码封装为数据,使代码简洁,易于理解。
二、函数式接口和定义
1、什么是函数式接口
函数式接口(FunctionalInterface)是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。Java中函数式接口被隐式转换为Lambda表达式,只有保证接口类中有且只有一个抽象方法,Java中的Lambda表达式才能对该方法进行推导。
2、函数式接口格式
在Java函数式接口类中,需要满足接口类中只能有一个抽象方法。总结如下:
- 接口有且仅有一个抽象方法;
- 允许定义静态方法;
- 允许定义默认方法;
- 允许java.lang.Object中的public方法;
在创建函数式接口时,可以在接口类上面加上@FunctionalInterface注解,这时编译器就可以对接口结构进行强制检查是否符合函数式接口规则,如果不符合规则就显示错误。当然,这个注解只是用于检查,即使不加上该注解,只要符合函数式接口规则一样也是函数式接口。
下面创建个演示的函数式接口,如下:
//@FunctionalInterface注解说明:
//使用该注解来定义接口,编译器会强制检查接口是否符合函数式接口规则(有且仅有一个抽象方法),如果不符合则会报错。
@FunctionalInterface
publicinterfaceMyInterface{
/**
*抽象方法(Jdk8以后接口类中方法可以省去publicabstract)
*/
publicabstract[返回值类型][方法名称](参数列表);
/**
*其它方法(Jdk8以后允许接口类中添加"默认方法"与"静态方法")
*/
...(略)
}
按照上面函数式接口,定义一个示例的函数式接口类,代码如下:
@FunctionalInterface
publicinterfaceMyCollection{
voidpush(Listlist);
}
3、函数式接口和Lambda表达式的关系
函数式接口和Lambda表达式的关系可以总结为:
- 函数式接口只包含一个操作方法;
- Lambda表达式只能操作一个方法;
- Java中的Lambda表达式核心就是一个函数式编程接口的实现。
4、当前JDK8中存在的函数式接口类
在JDK1.8之前,已经存在部分函数式接口,如下:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
在JDK8中新增了函数接口java.util.function包,里面包含了很多用来支持Java的函数式编程的接口类,如下:
| 类名称 | 描述信息 |
|---|---|
| BiConsumer |
代表了一个接受两个输入参数的操作,并且不返回任何结果。 |
| BiFunction |
代表了一个接受两个输入参数的方法,并且返回一个结果。 |
| BinaryOperator |
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果。 |
| BiPredicate |
代表了一个两个参数的boolean值方法。 |
| BooleanSupplier | 代表了boolean值结果的提供方。 |
| Consumer |
代表了接受一个输入参数并且无返回的操作。 |
| DoubleBinaryOperator | 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
| DoubleConsumer | 代表一个接受double值参数的操作,并且不返回结果。 |
| DoubleFunction |
代表接受一个double值参数的方法,并且返回结果。 |
| DoublePredicate | 代表一个拥有double值参数的boolean值方法。 |
| DoubleSupplier | 代表一个double值结构的提供方。 |
| DoubleToIntFunction | 接受一个double类型输入,返回一个int类型结果。 |
| DoubleToLongFunction | 接受一个double类型输入,返回一个long类型结果。 |
| DoubleUnaryOperator | 接受一个参数同为类型double,返回值类型也为double。 |
| Function |
接受一个输入参数,返回一个结果。 |
| IntBinaryOperator | 接受两个参数同为类型int,返回值类型也为int。 |
| IntConsumer | 接受一个int类型的输入参数,无返回值。 |
| IntFunction |
接受一个int类型输入参数,返回一个结果。 |
| IntPredicate | 接受一个int输入参数,返回一个布尔值的结果。 |
| IntSupplier | 无参数,返回一个int类型结果。 |
| IntToDoubleFunction | 接受一个int类型输入,返回一个double类型结果。 |
| IntToLongFunction | 接受一个int类型输入,返回一个long类型结果。 |
| IntUnaryOperator | 接受一个参数同为类型int,返回值类型也为int。 |
| LongBinaryOperator | 接受两个参数同为类型long,返回值类型也为long。 |
| LongConsumer | 接受一个long类型的输入参数,无返回值。 |
| LongFunction |
接受一个long类型输入参数,返回一个结果。 |
| LongPredicate | R接受一个long输入参数,返回一个布尔值类型结果。 |
| LongSupplier | 无参数,返回一个结果long类型的值。 |
| LongToDoubleFunction | 接受一个long类型输入,返回一个double类型结果。 |
| LongToIntFunction | 接受一个long类型输入,返回一个int类型结果。 |
| LongUnaryOperator | 接受一个参数同为类型long,返回值类型也为long。 |
| ObjDoubleConsumer |
接受一个object类型和一个double类型的输入参数,无返回值。 |
| ObjIntConsumer |
接受一个object类型和一个int类型的输入参数,无返回值。 |
| ObjLongConsumer |
接受一个object类型和一个long类型的输入参数,无返回值。 |
| Predicate |
接受一个输入参数,返回一个布尔值结果。 |
| Supplier |
无参数,返回一个结果。 |
| ToDoubleBiFunction |
接受两个输入参数,返回一个double类型结果 |
| ToDoubleFunction |
接受一个输入参数,返回一个double类型结果。 |
| ToIntBiFunction |
接受两个输入参数,返回一个int类型结果。 |
| ToIntFunction |
接受一个输入参数,返回一个int类型结果。 |
| ToLongBiFunction |
接受两个输入参数,返回一个long类型结果。 |
| ToLongFunction |
接受一个输入参数,返回一个long类型结果。 |
| UnaryOperator |
接受一个参数为类型T,返回值类型也为T。 |
5、JDK中常见的函数式接口类
上面java.util.function包提供了众多的函数式接口,其中常用的有:
- java.util.function.Predicate
:接收参数对象T,返回一个boolean类型结果。 - java.util.function.Comsumer
:接收参数对象T,不返回结果。 - java.util.function.Function
:接收参数对象T,返回结果对象R。 - java.util.function.Supplier
:不接收参数,提供T对象的创建工厂。 - java.util.function.UnaryOperator
:接收参数对象T,返回结果对象T。 - java.util.function.BinaryOperator
:接收两个T对象,返回一个T对象结果。
注:为了使易懂,下面示例中Lambda表达式没有使用的最简易写法,而是使用比较繁琐的写法。
(1)、java.util.function.Predicate
接口类作用:接收参数对象T,返回一个boolean类型结果。
接口类源码:
@FunctionalInterface publicinterfacePredicate{ /**abstract方法,接收一个参数,判断这个参数是否匹配某种规则,然后返回布尔值结果*/ booleantest(Tt); /**default方法,接收另外一个Predicate 类型参数进行"逻辑与"操作,返回一个新的Predicate*/ defaultPredicate and(Predicateother){ Objects.requireNonNull(other); return(t)->test(t)&&other.test(t); } /**default方法,接收另外一个Predicate 类型参数进行"逻辑或"操作,返回一个新的Predicate*/ defaultPredicate negate(){ return(t)->!test(t); } /**default方法,返回当前Predicate取反操作之后的Predicate*/ defaultPredicate or(Predicateother){ Objects.requireNonNull(other); return(t)->test(t)||other.test(t); } static Predicate isEqual(ObjecttargetRef){ return(null==targetRef) ?Objects::isNull :object->targetRef.equals(object); } }
使用示例:
publicclassPredicateExample{
/**这里创建一个Prodicate,设置验证秘钥的一个逻辑,然后返回并输出验证结果*/
publicstaticvoidmain(String[]args){
//创建Predicate及Lambda表达式与待实现的逻辑
Predicatevalidation=(Stringsecret)->{
return"123456".equals(secret);
};
//调用Predicate提供的test方法并输出结果
System.out.println(validation.test("123"));
System.out.println(validation.test("123456"));
}
}
日常开发中,需要对某个值进行判断操作,并且返回判断结果,这时可以考虑使用Predicate接口,以及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
(2)、java.util.function.Comsumer
接口类作用:接收参数对象T,不返回结果。
接口类源码:
@FunctionalInterface publicinterfaceConsumer{ /**abstract方法,接收一个参数,执行消费逻辑*/ voidaccept(Tt); /**default方法,将两个Consumer连接到一起,再进行消费*/ defaultConsumer andThen(Consumerafter){ Objects.requireNonNull(after); return(Tt)->{accept(t);after.accept(t);}; } }
使用示例:
/**这里创建一个Consumer,模拟发送消息并打印内容*/
publicclassConsumerExample{
publicstaticvoidmain(String[]args){
//创建Consumer及Lambda表达式与待实现的逻辑
Consumerconsumer=(Stringmessage)->{
System.out.println("发送消息内容:"+message);
};
//调用Consumer提供的accept方法
consumer.accept("测试消息");
}
}
日常开发中,需要对某个类型进行公共处理,并且不需要任何返回值,这时可以考虑使用Consumer接口及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
(3)、java.util.function.Function
接口类作用:接收参数对象T,返回结果对象R。
接口类源码:
@FunctionalInterface publicinterfaceFunction{ /**abstract方法,接收一个参数进行处理,然后返回处理结果R*/ Rapply(Tt); /**default方法,先执行参数(Function)的,再执行调用者(Function)*/ default Function compose(Functionbefore){ Objects.requireNonNull(before); return(Vv)->apply(before.apply(v)); } /**default方法,先执行调用者,再执行参数,和compose相反*/ default Function andThen(Functionafter){ Objects.requireNonNull(after); return(Tt)->after.apply(apply(t)); } /**返回当前正在执行的方法*/ static Function identity(){ returnt->t; } }
使用示例:
/**这里创建一个Function,对传入的参数进行验证,如果包含a字符就返回1,否则返回0*/
publicclassFunctionExample{
publicstaticvoidmain(String[]args){
//创建Function及Lambda表达式与待实现的逻辑
Functionfunction=(Stringstr)->{
returnstr.contains("a")?1:0;
};
//调用Function提供的apply方法
System.out.println(function.apply("abcd"));
System.out.println(function.apply("efgh"));
}
}
日常开发中,需要对某个类型数据进行操作,经过一系列逻辑后转换为一个新的类型进行返回,这时可以考虑使用Function接口及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
(4)、java.util.function.Supplier
接口类作用:不接收参数,提供T对象的创建工厂。
接口类源码:
@FunctionalInterface publicinterfaceSupplier{ /**abstract方法,设置业务逻辑,获取逻辑中创建的对象*/ Tget(); }
使用示例:
/**这里创建一个Supplier,用于生成随机ID,通过get方法获取生成的随机ID值*/
publicclassSupplierExample{
publicstaticvoidmain(String[]args){
//创建Supplier及Lambda表达式与待实现的逻辑
Suppliersupplier=()->{
returnUUID.randomUUID().toString();
};
//调用Supplier提供的get方法
System.out.println(supplier.get());
}
}
日常开发中,需要创建一个统一的工厂用于生成特定的产物完成特定的目标,这时就可以考虑使用Supplier接口及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
(5)、java.util.function.UnaryOperator
接口类作用:接收参数对象T,返回结果对象T。
接口类源码:
//可以看到UnaryOperator继承了Function接口 @FunctionalInterface publicinterfaceUnaryOperatorextendsFunction { /**static方法,接收一个参数,然后对其处理后再返回*/ static UnaryOperator identity(){ returnt->t; } }
使用示例:
/**这里创建一个UnaryOperator,接收一个字符串进行加工处理后返回新字符串*/
publicclassUnaryOperatorExample{
publicstaticvoidmain(String[]args){
//创建UnaryOperator及Lambda表达式与待实现的逻辑
UnaryOperatorunaryOperator=(Stringstr)->{
return"["+str+"]";
};
//调用UnaryOperator继承的Function提供的apply方法
System.out.println(unaryOperator.apply("hello"));
}
}
日常开发中,我们经常要对一个已有的对象进行操作修改,然后返回修改后的对象,这时就可以考虑使用UnaryOperator接口及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
(6)、java.util.function.BinaryOperator
接口类作用:接收两个T对象,返回一个T对象结果。
接口类源码:
@FunctionalInterface publicinterfaceBinaryOperatorextendsBiFunction { /**abstract方法,通过比较器Comparator来比较两个元素中较小的一个作为返回值返回*/ publicstatic BinaryOperator minBy(Comparatorcomparator){ Objects.requireNonNull(comparator); return(a,b)->comparator.compare(a,b)<=0?a:b; } /**通过比较器Comparator来比较两个元素中较大的一个作为返回值返回*/ publicstatic BinaryOperator maxBy(Comparatorcomparator){ Objects.requireNonNull(comparator); return(a,b)->comparator.compare(a,b)>=0?a:b; } }
使用示例:
/**这里创建一个BinaryOperator,比较传入的两个参数哪个值最大,返回最大值*/
publicclassBinaryOperatorExample{
publicstaticvoidmain(String[]args){
//创建BinaryOperator及Lambda表达式与待实现的逻辑
BinaryOperatorbinaryOperator=(Integert1,Integert2)->{
returnt1>t2?t1:t2;
};
//调用BinaryOperator继承的BiFunction提供的apply方法
System.out.println(binaryOperator.apply(1,2));
}
}
在使用这几种基本函数接口时传入参数T不能是基本类型,如BinaryOperator中T不能设置为int,只能使用Integer包装类,这也限制了Lambda表达式中设置参数时候,使用包装类替换基本类型。
日常开发中,我们有时候会对两个对象进行操作,执行一些操作逻辑后返回结果,这时就可以考虑使用BinaryOperator接口及它的Lambda表达式的实现,能方便的实现我们业务上的一些功能。
三、Lambda表达式基本语法
1、Lambda表达式的组成
Lambda表达式的组成可以拆分为:
- 声明:与Lambda表达式绑定的接口类型。
- 参数:参数包含在一对()中,和绑定的接口中的抽象方法中的参数个数及顺序一致。
- 操作符:->
- 执行代码块:执行代码块包含在一对{}中,出现在操作符的右侧。
[接口声明]=(参数)->{执行代码块}
2、Lambda表达式的格式
Lambda表达式可以分为下面几种格式:
- 无参数,无返回值;
- 有一个参数,无返回值;
- 左侧只有一个参数,小括号可以省略不写;
- 有两个以上参数,有返回值,并且Lambda体中有多条语句;
- 若右侧Lambda体中,只有一条语句,return和大括号都可以省略不写;
- Lambda表达式的参数列表的数据类型可以省略不写,jvm编译器会进行上下文推断出,数据类型“类型推断”;
(1)、无参数,无返回值
()->System.out.println("测试");
(2)、有一个参数,无返回值
(x)->System.out.println(x);
(3)、左侧只有一个参数,小括号可以省略不写
x->System.out.println(x);
(4)、有两个以上参数,有返回值,并且Lambda体中有多条语句
Comparatorcomparator=(x,y)->{ System.out.println("测试"); returnInteger.compare(x,y); };
(5)、若右侧Lambda体中,只有一条语句,return和大括号都可以省略不写
ComparatorComparator=(x,y)->Integer.compare(x,y);
(6)、Lambda表达式的参数列表的数据类型可以省略不写,JVM在运行时,会自动根据绑定的抽象方法中的参数,进行数据类型推导
(Integerx,Integery)->Integer.compare();
四、Lambda表达式中变量作用域
Java中的变量捕获与变量隐藏:
- 变量捕获:局部类和匿名内部类可以访问被final修饰的封闭块内的局部变量。
- 变量隐藏:在一个类中,子类中的成员变量如果和父类中的成员变量同名,那么即使他们类型不一样,只要名字一样,父类中的成员变量都会被隐藏。
在局部类和匿名内部类都存在变量捕获与变量隐藏,而在Lambda表达式中则只支持变量捕获。
下面是对这作用域得演示示例:
(1)、匿名内部类:
publicclassVariableExample{
/**成员变量*/
Stringstr1="成员变量";
publicvoidinnerClass(){
//方法内部变量
Stringstr2="方法内部变量";
//使用匿名内部类创建线程
newThread(newRunnable(){
//匿名内部类内部变量
Stringstr3="匿名内部类内部变量";
@Override
publicvoidrun(){
/*访问变量*/
System.out.println("匿名内部类输出:"+str1);
System.out.println("匿名内部类输出:"+str2);
System.out.println("匿名内部类输出:"+str3);
/*修改变量*/
str1="修改访问成员变量";
//str2="修改访问方法内部变量";//不能进行修改,默认推导变量的修饰符final
str3="修改访问匿名内部类内部变量";
/*在匿名内部类中定义和类外部变量一样名称的变量*/
Stringstr1="重新命名成员变量";
Stringstr2="重新命名方法内部变量";
}
}).start();
}
/**Main方法*/
publicstaticvoidmain(String[]args){
VariableExamplevariableExample=newVariableExample();
//匿名内部类
variableExample.innerClass();
}
}
(2)、Lambda表达式:
publicclassVariableExample{
/**成员变量*/
Stringstr1="成员变量";
publicvoidlambdaExpression(){
//方法内部变量
Stringstr2="方法内部变量";
newThread(()->{
//Lambda内部变量
Stringstr3="Lambda内部变量";
/*访问变量*/
//访问成员变量
System.out.println("Lambda表达式输出:"+str1);
//访问方法内部变量
System.out.println("Lambda表达式输出:"+str2);
//访问匿名内部类内部变量
System.out.println("Lambda表达式输出:"+str3);
/*修改变量*/
str1="修改访问成员变量";
//str2="修改访问方法内部变量";//不能进行修改,默认推导变量的修饰符final
str3="修改访问匿名内部类内部变量";
/*在Lambda中定义和类外部变量一样名称的变量*/
Stringstr1="重新命名成员变量";
//Stringstr2="重新命名方法内部变量";//不能命名,lambda不支持变量隐藏
}).start();
}
/**Main方法*/
publicstaticvoidmain(String[]args){
VariableExamplevariableExample=newVariableExample();
//匿名内部类
variableExample.innerClass();
//Lambda表达式
variableExample.lambdaExpression();
}
}
五、Lambda表达式方法重载问题
当使用Lambda表达式,调用一个类中的重载方法,且方法中的参数为都为函数接口,函数接口中定义的方法接收的参数类型相同,这时候Lambda是无法推断出要调用哪个方法。
函数接口A:
@FunctionalInterface
interfaceMyInterfaceA{
voidpush(Stringparam);
}
函数接口B:
@FunctionalInterface
interfaceMyInterfaceB{
voidpull(Stringparam);
}
示例,实现方法重载与测试的Main方法:
publicclassLambdaOverloadExample{
//重载方法A
publicstaticvoidmethod(MyInterfaceAmyInterfaceA){
myInterfaceA.push("hello1");
}
//重载方法B
publicstaticvoidmethod(MyInterfaceBmyInterfaceB){
myInterfaceB.pull("Hello2");
}
/**Main方法*/
publicstaticvoidmain(String[]args){
//使用匿名内部类
method(newMyInterfaceA(){
@Override
publicvoidpush(Stringparam){
System.out.println(param);
}
});
method(newMyInterfaceB(){
@Override
publicvoidpull(Stringparam){
System.out.println(param);
}
});
//使用Lambda表达式
//method(param->System.out.println(param));//编译器提示错误,表示无法推断使用哪个参数
}
}
上面注掉的那部分代码,在编辑器中直接提示错误,很显然Lambda表达式无法直接推断出使用哪个类中的重载方法。其实,只要明确告诉Lambda表达式使用哪个参数,就可以很简单的解决问题,比如以上面的例子,在Lambda表达式使用method方法时,将参数类型转换为对应的要使用的类型就可以解决这个问题,代码如下:
//转换参数为MyInterfaceA method((MyInterfaceA)param->System.out.println(param)); //转换参数为MyInterfaceB method((MyInterfaceB)param->System.out.println(param));
按上面进行修改后就可以正常使用Lambda表达式了,如果不习惯也可以使用匿名内部类进行方法调用,内名内部类是没有相关问题的。
六、Lambda表达式方法引用
方法引用本质上就是对方法调用的简化,方法引用和函数式接口绑定,在使用过程中会创建函数式接口的实例,是结合Lambda表达式的一种特性。在应用过程中,方法引用常分为:
- 静态方法引用
- 实例方法引用
- 构造方法引用
- 特定类型的任意对象实例方法引用
注意:在使用Lmabda方法引用时虽然能够简化代码,但是在实际开发中不可因需要简化代码而过度使用方法引用,因为他会在很大程度上降低代码可读性。
1、创建示例的实体类
为了下面示例方便,我们首先创建一个Person实体类,如下:
publicclassPerson{
/**姓名*/
privateStringname;
/**岁数*/
privateintage;
publicPerson(){
}
publicPerson(Stringname,intage){
this.name=name;
this.age=age;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
@Override
publicStringtoString(){
return"Person{name="+name+",age="+age+"}";
}
}
2、静态方法引用示例
静态方法的引用的使用:静态方法所在类.方法名称()–>静态方法所在类::方法名称
创建一个使用静态方法引用的示例类:
publicclassStaticMethodExample{
/**测试的静态方法*/
publicstaticintcompareAge(Personp1,Personp2){
returnp1.getAge()-p2.getAge();
}
publicstaticvoidmain(String[]args){
//创建Person集合
ListpersonList=newArrayList<>();
personList.add(newPerson("Wangqin",26));
personList.add(newPerson("Liming",22));
personList.add(newPerson("Alisi",18));
personList.add(newPerson("Jerry",31));
//按岁数进行排序,使用静态方法引用
personList.sort(StaticMethodExample::compareAge);
}
}
3、实例方法引用示例
实例方法的引用的使用:创建类型对应一个对象–>对应应用::实例方法名称
创建一个封装实例方法的类:
publicclassPersonUtil{
/**测试的实例方法*/
publicintcompareAge(Personp1,Personp2){
returnp1.getAge()-p2.getAge();
}
}
创建一个使用实例方法引用的示例类:
publicclassInstanceMethodExample{
publicstaticvoidmain(String[]args){
//创建Person集合
ListpersonList=newArrayList<>();
personList.add(newPerson("Wangqin",26));
personList.add(newPerson("Liming",22));
personList.add(newPerson("Alisi",18));
personList.add(newPerson("Jerry",31));
//按岁数进行排序,
PersonUtilpersonUtil=newPersonUtil();
//引用实例方法
personList.sort(personUtil::compareAge);
}
}
4、构造方法引用示例
构造方法的引用的使用:绑定函数式接口
创建一个函数式接口,且设置接收参数和Person的构造方法相同,返回Person对象的方法定义:
@FunctionalInterface
publicinterfacePersonConstructor{
PersoninitInstance(Stringname,intage);
}
创建一个使用构造方法引用的示例类
publicclassLambdaConstructorMethodExample{
publicstaticvoidmain(String[]args){
//创建Person集合
ListpersonList=newArrayList<>();
personList.add(newPerson("Wangqin",26));
personList.add(newPerson("Liming",22));
personList.add(newPerson("Alisi",18));
personList.add(newPerson("Jerry",31));
//构造方法引用
PersonConstructorpersonConstructor=Person::new;
Personperson=personConstructor.initInstance("linda",18);
System.out.println(person);
}
}
5、特定类型的任意对象实例方法引用示例
特定类型的任意对象实例方法引用示例:特定类型::特定类型的方法
以下是对特定类型的任意对象的实例方法的引用的示例:
publicclassLambdaExample{
publicstaticvoidmain(String[]args){
//创建字符串集合
ListstrList=newArrayList<>();
strList.add("Jerry");
strList.add("Mini");
strList.add("Kary");
strList.add("walls");
//使用集合的sort方法,按照String的compareToIgnoreCase进行排序(比较字符串hash值)
strList.sort(String::compareToIgnoreCase);
System.out.println(strList);
}
}
这里根据定义的集合strList去推导目标类型参数值,如果不符合后面传入的方法引用所对应的类型,将报错。该方法参考等效Lambda表达式String::compareToIgnoreCase的参数列表(Stringa,Stringb),其中a和b是用于更好地描述这个例子中的任意名称。方法引用将调用该方法a.compareToIgnoreCase(b)。
到此这篇关于Java8如何使用Lambda表达式简化代码的文章就介绍到这了,更多相关Java8用Lambda表达式简化代码内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!