摘要:的本质需求按照产品的重量进行升序排序此处使用匿名内部类的设计,但掺杂了较多的语法噪声,引入了不必要的复杂度。使用表达式,可以进一步消除语法噪声,简化设计。方法引用其本质是具有单一方法调用的表达式的语法糖表示。
Lambda的本质
需求1. 按照产品的重量进行升序排序
此处使用「匿名内部类」的设计,但掺杂了较多的语法噪声,引入了不必要的复杂度。
Collections.sort(repo, new Comparator() { @Override public int compare(Product p1, Product p2) { return p1.getWeight().compareTo(p2.getWeight()); } });
使用Lambda表达式,可以进一步消除语法噪声,简化设计。
Collections.sort(repo, (Product p1, Product p2) -> p1.getWeight().compareTo(p2.getWeight()));
也就是说,Lambda其本质是「匿名内部类」的一种「语法糖」表示,存在如下3个方面的特征:
Anonymous Function:匿名的函数
Passed Around:可作为参数或返回值进行传递,甚至可以自由地存储在变量中
Concise:相对于匿名内部类的样板代码(Boilerplate),Lambda更加简洁漂亮
类型推演借助编译器「类型推演」的能力,可以进一步简化Lambda表达式。
Collections.sort(repo, (p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));Lambda的形式
形式1:(parameters) -> expression
Collections.sort(repo, (p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));
形式2:(parameters) -> { statements; }
Collections.sort(repo, (p1, p2) -> { return p1.getWeight().compareTo(p2.getWeight()); });默认方法
先看看java.util.Collections.sort的实现,其中java.util.Collections是一个典型的「工具类」。
public final class Collectins { private Collectins() { } public staticvoid sort(List extends T> l, Comparator super T> c) { l.sort(c); } }
这样的设计是反OO,为此可以将其sort搬迁至List接口中去。
public interface Listextends Collection { default void sort(Comparator super E> c) { ... } ... }
default方法类似于C++的虚函数。从某种意义上看,default的引入使得Java又重新回到了「多重继承」的怀抱,为设计带来了更大的弹性。
为此,设计可重构为更加符合OO的风格。
repo.sort((p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));方法引用
借助Comparator.comparing的工厂方法,结合「方法引用」可进一步提高代码的可读性。
import static java.util.Comparator.comparing; repo.sort(comparing(Product::getWeight));
方法引用其本质是具有单一方法调用的lambda表达式的「语法糖」表示。
级联方法需求2. 按照产品的重量降序排序
repo.sort(comparing(Product::getWeight) .reversed()); .thenComparing(Product::getCountry));
需求3. 如果重量相同,则按照出厂国的自然序排序
repo.sort(comparing(Product::getWeight) .reversed() .thenComparing(Product::getCountry));深入理解Comparator
有且仅有一个抽象方法的接口,称为「函数式接口」,使用@FunctionalInterface的注解标识。函数式接口中「抽象方法」描述了Lambda表达式的「原型」。
() -> {}也是一个合法的Lambda表达式,与Runnable接口相匹配。
也就是说,一个「函数式接口」可包含如下元素:
Abstract Method:有且仅有一个抽象方法
Default Methods:0个或多个默认方法
Static Methods: 0个或多个静态方法
对照前面的列子,可洞悉Comparator设计的巧妙。
repo.sort(comparing(Product::getWeight) .reversed());
其中,Comparator就是一个典型的函数式接口。通过「方法级联」设计了一套简单的Comparator的DSL,增强了用户的表达力。
@FunctionalInterface public interface Comparator{ int compare(T o1, T o2); default Comparator reversed() { return Collections.reverseOrder(this); } static > Comparator comparing( Function super T, ? extends U> extractor) { return (c1, c2) -> extractor.apply(c1) .compareTo(extractor.apply(c2)); } }
其中,Comprator.compring的实现稍微有点复杂。
comparing是一个静态工厂方法,它生产一个Comparator
comparing是一个高阶函数;
接受一个函数:Function super T, ? extends U> extractor
返回一个函数:Comparator
comparing是一个语法糖,结合「方法引用」的机制,极大地改善了用户接口的表达力;
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65723.html
摘要:局部变量表达式的方法体与嵌套代码块有着相同的作用域。在表达式中不允许声明一个与局部变量同名的参数或者局部变量。不可变的约束只作用在局部变量上,如果是一个实例变量或者闭合类的静态变量,那么不会有任何错误被报告出来即使结果同样未定义。 完整的Java学习的路线图可以参考:我的编程之路--知识管理与知识体系 Lambda&Closures Java8 Lambda表达式10个示例 闭包一般指...
摘要:一表达式匿名内部类最大的问题在于其冗余的语法,比如前面的中五行代码仅有一行是在执行任务。总结基于词法作用域的理念,表达式不可以掩盖任何其所在上下文的局部变量。 转载请注明出处:https://zhuanlan.zhihu.com/p/20540175 在介绍Lambda表达式之前,我们先来看只有单个方法的Interface(通常我们称之为回调接口): public interface...
摘要:之前,使用匿名类给苹果排序的代码是的,这段代码看上去并不是那么的清晰明了,使用表达式改进后或者是不得不承认,代码看起来跟清晰了。这是由泛型接口内部实现方式造成的。 # Lambda表达式在《Java8实战》中第三章主要讲的是Lambda表达式,在上一章节的笔记中我们利用了行为参数化来因对不断变化的需求,最后我们也使用到了Lambda,通过表达式为我们简化了很多代码从而极大地提高了我们的...
大概一年多之前,我对java8的理解还仅限一些只言片语的文章之上,后来出于对函数式编程的兴趣,买了本参考书看了一遍,然后放在了书架上,后来,当我接手大客户应用的开发工作之后,java8的一些工具,对我的效率有了不小的提升,因此想记录一下java8的一些常用场景,我希望这会成为一个小字典,能让我免于频繁翻书,但是总能找到自己想找的知识。 用于举例的model: @Data public class ...
摘要:引入了与此前完全不同的函数式编程方法,通过表达式和来为下的函数式编程提供动力。命令式编程语言把对象变量和流转当作一等公民,而函数式编程在此基础上加入了策略变量这一新的一等公民。 Java8引入了与此前完全不同的函数式编程方法,通过Lambda表达式和StreamAPI来为Java下的函数式编程提供动力。本文是Java8新特性的第一篇,旨在阐释函数式编程的本义,更在展示Java是如何通...
阅读 4149·2021-09-22 15:34
阅读 2763·2021-09-22 15:29
阅读 489·2019-08-29 13:52
阅读 3350·2019-08-29 11:30
阅读 2258·2019-08-26 10:40
阅读 831·2019-08-26 10:19
阅读 2255·2019-08-23 18:16
阅读 2310·2019-08-23 17:50