Java8的Lambda表达式你真的会吗
理解Lambda
Lambda表达式可以是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为,也就是行为参数化,将不同的行为作为参数传入方法。
随着函数式编程思想的引进,Lambda表达式让可以用更加简洁流畅的代码来代替之前冗余的Java代码。
口说无凭,直接上个例子吧。在Java8之前,关于线程代码是这样的:
classTaskimplementsRunnable{
@Override
publicvoidrun(){
System.out.println("Java8之前实现Runnable接口中的run方法");
}
}
Runnablet=newTask();
我们定义了一个Task类,让它实现Runnable接口,实现仅有的run方法,我们希望执行的线程体虽然只有一句话,但我们仍然花了大量大代码去定义。为了简化,我们可以采用匿名内部类的方式:
RunnabletaskBeforeJava8=newRunnable(){
@Override
publicvoidrun(){
System.out.println("Java8之前的写法,传入匿名类");
}
};
但是,其实还是不够简洁,我们用Lambda的写法是这样的:
//java8之后
RunnabletaskAfterJava8=()->System.out.println("Java8之后的写法,lambda表达式");
我们仅仅使用()和->就完成了这件事,是不是非常简洁呢?如果你觉得虽然Lambda写法简洁,但是它的规则让人摸不着头脑,那就跟着我接下去学叭。
基础语法
(parameters)->action
(parameters)->expression
(parameters)->{statements;}
parameters代表变量,可以为空,可以为单,可以为空,你能想到的方式他都可以。
action是实现的代码逻辑部分,可以是一行代码expression,也可以是一个代码片段statements。如果是代码片段,需要加上{}。
下面是一些合法的示例,你可以看看有没有掌握:
| 表达式 | 描述 |
|---|---|
| ()->1024 | 不需要参数,返回值为1024 |
| x->2*x | 接收参数x,返回其两倍 |
| (x,y)->x-y | 接收两个参数,返回它们的差 |
| (intx,inty)->x+y | 接收两个int类型参数,返回他们的和 |
| (Strings)->print(s) | 接收一个String对象,并打印 |
函数式接口
@FunctionalInterface//此注解作用的接口只能拥有一个抽象方法
publicinterfaceRunnable{
publicabstractvoidrun();
}
在这里,@FunctionalInterface注解是非必须的,有点类似于@Override,起强调作用,如果你的接口标注该注解,却没有遵循它的原则,编译器会提示你修改。
常用的函数式接口
JDK原生为我们提供了一些常用的函数式编程接口,让我们在使用他们编程时,不必关心接口名,方法名,参数名,只需关注它的参数类型,参数个数,返回值。
| 接口 | 参数 | 返回值 | 类别 | 示例 |
|---|---|---|---|---|
| Consumer | T | void | 消费型接口 | 打印输出某个值 |
| Supplier | None | T | 供给型接口 | 工厂方法获取一个对象 |
| Function | T | R | 函数型接口 | 获取传入列表的总和 |
| Predicate | T | boolean | 断言型接口 | 判断是否以summer为前缀 |
消费型接口
@FunctionalInterface//此注解作用的接口只能拥有一个抽象方法
publicinterfaceRunnable{
publicabstractvoidrun();
}
供给型接口
/**
*供给型接口,无参数,返回T
*/
publicstaticvoidsupplierTest(){
Supplier
断言型接口
/**
*断言型传入参数T,返回boolean
*/
publicstaticvoidpredicateTest(){
Predicatepredicate=name->name.startsWith("summer");
System.out.println(predicate.test("summerday"));
}
函数型接口
/**
*函数型接口传入T返回R
*/
publicstaticvoidfunctionTest(){
Listlist=newArrayList<>(Arrays.asList(1,2,3,4,5));
Function,Integer>function=num->{
intres=0;
for(intn:list){
res+=n;
}
returnres;
};
Integernum=function.apply(list);
System.out.println(num);
}
方法引用
方法引用可以看作特定Lambda表达式的快捷写法,主要分为以下两种:
- 指向静态方法的方法引用
- 指向现有对象的实例方法的方法引用
/**
*方法引用
*1.指向静态方法的方法引用
*2.指向现有对象的实例方法的方法引用
*
*@authorSummerday
*/
publicclassMethodReferenceTest{
publicstaticListgetList(Listparams,Predicatefilter){
Listres=newLinkedList<>();
for(Stringparam:params){
if(filter.test(param)){
res.add(param);
}
}
returnres;
}
//静态方法
publicstaticbooleanisStartWith(Stringname){
returnname.startsWith("sum");
}
publicstaticvoidmain(String[]args){
Listparams=Arrays.asList("summerday","tqbx","天乔巴夏","summer","");
//静态方法的方法引用getList(params,name->MethodReferenceTest.isStartWith(name));
Listlist=getList(params,MethodReferenceTest::isStartWith);
System.out.println(list);
//指向现有对象的实例方法的方法引用getList(params,name->name.isEmpty());
Listsum=getList(params,String::isEmpty);
System.out.println(sum);
}
}
数组引用
/**
*数组引用
*@authorSummerday
*/
publicclassArrayReferenceTest{
publicstaticvoidmain(String[]args){
//普通lambda
Functionfun1=x->newString[x];
String[]res1=fun1.apply(10);
System.out.println(res1.length);
//数组引用写法
Functionfun2=String[]::new;
String[]res2=fun2.apply(10);
System.out.println(res2.length);
}
}
构造器引用
/**
*构造器引用
*@authorSummerday
*/
publicclassConstructorReferenceTest{
publicstaticvoidmain(String[]args){
//普通lambda
Suppliersup=()->newUser();
//构造器引用
Suppliersupplier=User::new;
Useruser=supplier.get();
System.out.println(user);
}
}
classUser{
}
总结
- lambda表达式没有名称,但有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常的列表。
- lamda表达式让你可以将不同的行为作为参数传入方法。
- 函数式接口是仅仅声明了一个抽象方法的接口。只有在接受函数式接口的地方才可以使用lambda表达式。
- lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并将整个表达式作为函数式接口的一个实例。
- Java8自带了一些常用的函数式接口,包括Predicate,Function,Supplier,Consumer,BinaryOperator。
- 方法引用让你重复使用现有的方法实现并直接传递他们:Classname::method。
到此这篇关于Java8的Lambda表达式你真的会吗的文章就介绍到这了,更多相关Java8的Lambda表达式内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!