JDK8可以说是Java发布以来最大的变化,而这里一连串的变化,lambda可以说是让Java这个死板的中年大叔变成了油腻男,少一点古板,多一点弹性。这也是对Java语法复杂死板的抱怨的有力回击。以下为本文目录,按需食用。深入理解lambda什么是Lambda,它解决什么问题?Lambda语法基本概念函数式接口方??法和构造函数参考静态方法参考实例方法参考Lambda参数行为总结函数式接口附录什么是Lambda,它解决什么问题?在讲Lambda之前,我们需要回顾一个概念,匿名内部类:实现了接口但没有名字的类就成为匿名内部类。通常用在通过new关键字创建的方法中。一般来说,这类类并没有太复杂的聚合逻辑,只是解决单一的逻辑问题,比如排序、线程等。让我们通过一个例子来看看Java在处理这种场景方面的演变。内部类privatestaticclassIntegerComparatorimplementsComparator{@Overridepublicintcompare(Integera,Integerb){returnb-a;}}Listlist=Arrays.asList(1,2,3,4,5,6,7,8,9);Collections.sort(list,newIntegerComparator());log.info("排序的列表:{}",列表);通常我们不用这个,因为IntegerComparator只是一次性使用,没有复用的需求,所以这个操作有点繁琐,于是就有了匿名内部类AnonymousinnerclassListlist=Arrays.asList(1,2,3,4,5,6,7,8,9);Collections.sort(list,newComparator(){@Overridepublicintcompare(Integera,Integerb){返回b-a;}});log.info("列表排序:{}",list);但是相对于内部静态类,它只是内联代码,本质上并没有减少代码量,所以这也是推出Lambda的主要原因。LambdaListlist=Arrays.asList(1,2,3,4,5,6,7,8,9);//list.sort(Integer::compareTo);list.sort((a,b)->b-a);log.info("列表排序:{}",list);可以看出,在Lambda语法之前,Java其实已经优化了匿名内部类的使用体验,但是,在借鉴了其他语言的语法特点之后,Lambda表达式更加彻底。通过剔除示例代码,只保留逻辑代码,大大提升了书写和阅读体验。所以Lambda主要是提升匿名内部类的编写体验。Lambda的基本概念在数学和计算机科学中,Lambda表达式(在维基百科上也称为高阶函数)是至少满足以下条件之一的函数:接收一个或多个函数作为输入输出一个函数先验到Java8,没有办法编写一个独立的函数,方法经常被用来代替函数,但它们始终是对象或方法的一部分。Lambda表达式现在提供了一种更接近独立函数概念的方法。作为匿名内部类的替代品,它有以下优点:语法简洁,允许省略访问修饰符、返回类型、参数类型等。参数行为提高代码复用性大量开箱即用的函数式工具,在一般场景下带来Lambda开箱即用的工具语法Lambda表达式由参数列表和方法体组成,用->分隔,所以下面都是合法的//单参数p->p.translate(1,1)i->newPoint(i,i+1)//一个或多个参数,用()表示和普通方法一致()->16(x,y)->x+y//设置参数类型,通常可以省略,因为可以从后面的方法声明中推断出来,(intx,inty)->x+y//jdk11有lambda中可以使用增强的var(varx,vary)->x+y如果我们用抽象语法来表达lambda表达式,就像这样:args->expr//有时如果方法有返回值,并且实现逻辑比较复杂,不能一行表达,可以写args->{returnexpr;}用lambda表达函数式接口,必须继承函数式接口,即只有一个的接口abstractmethod,当一个接口满足这样的条件时,在JDK8中可以使用Lambda表达式给接口添加注解@FunctionalInterface来表明一个接口是函数式接口。我们可以在java.util.function包下查看所有JDK8开箱即用的功能接口。函数接口表达式解释Function{Rapply(Tt);}T->R接受参数T并生成结果RBiFunction{Rapply(Tt,Uu);}(T,U)->R接受参数T,U,并产生一个结果RPredicate{booleantest(Tt);}T->Boolean接受参数T,返回一个布尔值Supplier{Tget();}()->TproducermodeConsumer{voidaccept(Tt);}T->()consumermode除了这些功能接口之外,还有很多其他的衍生接口,但大部分都是为了完善original一些接口是专门为类型参数的表现而创建的。这里主要介绍Supplier和Consumer的使用场景,以了解Lambda的设计思想。Consumer@Slf4jpublicclassConsumerDemo{publicstaticvoidmain(String[]args){//打印参数Consumerprinter=t->System.out.println(t);//正如Consumer的文档所说,是Operatesthroughsideeffects。//这表明集合中的所有元素都是通过副作用操作处理的Consumer>odd=list->{for(inti=0;iconsumer){consumer.accept(msg);}}Supplier本例通过Supplier@Slf4jpublicclassSupplierDemo创建一个随机数生成器{//RandomGeneratorpublicstaticfinalRandomrandom=newRandom(10086L);publicstaticvoidmain(String[]args){//打印随机数Consumerprinter=t->log.info("{}",t);//生成随机数SupplierrandomGenerator=()->random.nextInt(0,100);//直接使用printer.accept(randomGenerator.get());//通过方法调用printer.accept(randomInt(randomGenerator));printer.accept(randomInt(randomGenerator));}publicstaticIntegerrandomInt(SupplierrandomGenerator){returnrandomGenerator.get();}}方法和构造函数参考Lambda和匿名内部类相比就够了足够简短,但我们可以更简洁//printConsumer>printer=t->System.out.println(t);//方法参考Consumer>printer=System.out::println;varlist=Arrays.asList(1,2,3,4,5,6,7,8,9);//将列表从小到大排序list.sort((o1,o2)->o1-o2);//方法参考list.sort(Integer::compare);通过代码,我们确实发现Lambda表达式更加简洁,这种写法有个名字,叫做方法引用,和JDK8一起引入的方法引用可以分为以下四类。名称语法Lambda等同于发布一个静态方法引用RefType::staticMethod(args)->RefType.staticMethod(args)一个实例方法引用expr::instMethod(args)->expr.instMethod(args)一个未绑定的实例方法引用RefType::staticMethod(arg0,rest)->arg0.instMethod(rest)构造函数引用ClsName::new(args)->newClsName(args)####静态方法引用静态方法引用只需要class和staticmethod()使用::分隔,如ToIntFunctiontoInt=str->Integer.valueOf(str);//方法参考ToIntFunctiontoInteger=Integer::valueOf;varlist=Arrays.asList(1,2,3,4,5,6,7,8,9);list.sort((o1,o2)->o2-o1);//方法参考list.sort(Integer::compare);实例方法引用强度方法引用分为绑定实例方法引用和未绑定实例方法引用。绑定的实例方法引用与静态方法很接近,使用ObjectReference::Identifier代替ReferType::Identifierstr->System.out.print(str)//方法引用System.out::print````非-绑定方法,不需要在上下文中绑定一个接收者(上例中的`System.out`对象)user->user.getName()//方法参考user::getName####构造函数参考```javaStreamstringStream=Stream.of("a.txt","b.txt","c.txt");StreamfileStream=stringStream.map(str->newFile(str))//引用方法StreamfileStream=stringStream.map(File::new);```##Lambda参数的行为化在Java8之前,方法参数不能传递给方法,只能传递状态,代码那么多具有类似行为无法复制但是,Lambda的引入解决了这个问题。通过将重复的、相似的代码逻辑抽象成精心设计和实现的功能接口,可以实现方法重用。这里我们以文章发布作为最终的综合示例,展示Lambda参数行为化带来的更深层次的逻辑应用。```java@Slf4jpublicclassPredicateDemo{//不再需要publicvoidpublish(LongarticleId){vararticle=get(articleId);if(Objects.equals(article.getPublished(),Boolean.FALSE)){log.info("发布文章:{}",article.getId());}else{//错误日志或忽略}}//不再需要publicvoidunpublish(LongarticleId){vararticle=get(articleId);if(Objects.equals(article.getPublished(),Boolean.TRUE)){log.info("取消发布文章:{}",article.getId());}else{//Errorlogorjustomit}}//Lambda的参数化行为带来了API实现层面统一的可能性//通过Predicate来处理文章的发布和取消发布逻辑,以及异常处理publicvoiddoPublish(LongarticleId,Booleanstatus,Predicatepredicate){vararticle=get(articleId);如果(predicate.test(article)){article.setPublished(status);log.info("设置文章状态为:{}",status);}else{log.error("IllegalStatusofArticle{}toset:{}",article,status);}}publicstaticvoidmain(String[]args){PredicateDemopredicateDemo=newPredicateDemo();//创建默认设置predicateDemo.doPublish(1L,Boolean.TRUE,p->Objects.equals(p.getPublished(),Boolean.FALSE));predicateDemo.doPublish(2L,Boolean.FALSE,p->Objects.equals(p.getPublished(),Boolean.TRUE));//创建默认predicateDemo.doPublish(1L,Boolean.TRUE,p->Objects.equals(p.getPublished(),Boolean.TRUE));predicateDemo.doPublish(2L,Boolean.FALSE,p->Objects.equals(p.getPublished(),Boolean.FALSE));}publicArticleget(Longid){returnfindAll()。得到(身份证);}publicstaticMapfindAll(){returnMap.of(1L,newArticle(1L,"value1",false),2L,newArticle(2L,"value2",true));}}@Getter@Setter@AllArgsConstructor@ToStringclass文章{privateLongid;私有字符串名称;privateBooleanpublished;}```##总结到这里,Lambda的介绍就结束了,剩下的就是让你了解Lambda的思维方式,熟悉`java.util.function`,然后使用它在自己的项目中小范围内,了解并掌握Lambda的思维方式,可以显着提高Java编程的乐趣。改进“匿名内部类”带来的巨大改进使得在Java8中引入“Stream”成为可能,但这是另一个话题。##任数接口附件|当前界面|首选接口||----------------------|------------------||函数<整数,R>|内部函数||函数<长,R>|长函数||函数<双精度,R>|双函数||函数<双精度,整数>|DoubleToIntFunction||功能<双,长>|双长函数||函数<长,双>|长到双函数||函数<长整型>|LongToInt函数||函数|ToIntFunction||函数|ToLongFunction||函数|ToDoubleFunction||函数|一元运算符||双函数|二元运算符||消费者<整数>|内部消费者||消费者<双>|双消费者||消费者<长>|长消费者||BiConsumer|ObjIntConsumer||BiConsumer|ObjLongConsumer||BiConsumer|ObjDoubleConsumer||谓词<整数>|整数谓词||谓词<双>|双谓词||谓词<长>|长谓词||供应商<整数>|国际供应商||供应商<双>|双供应商||供应商<长>|长供应商||供应商<布尔值>|布尔供应商||一元运算符<整数>|整数运算符||一元运算符<双>|双元运算符||一元运算符<长>|长一元运算符||二元运算符<整数>|整数二进制运算符||二元运算符<长>|长二进制运算符||二元运算符<双>|双二进制运算符||函数|谓词|