- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
代码示例: java.lambda.LambdaExpression 。
lambda
表达式本质上是对匿名内部类实例的一种简化写法。 有以下 List<Integer> 对象:
List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 2, 4, 6, 8, 10);
在对 List 进行从小大大排序时,会用到 List#sort(Comparator) 方法,需要传递实现 Comparator 接口的对象作为参数:
default void sort(Comparator<? super E> c) {
// 省略方法体
}
可以想到有如下四种不同的代码编写的方式.
Comparator
的实现类 根据需求,手动实现 Comparator 接口:
public class AscComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}
然后,创建 AscComparator 实例,传给 List#sort(Comparator) 方法:
Comparator<Integer> ascComparator = new AscComparator();
list.sort(ascComparator);
Comparator
的匿名对象 可以直接创建 Comparator 的匿名对象,然后传给 List#sort(Comparator) 方法:
Comparator<Integer> anonymousComparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
list.sort(anonymousComparator);
等价于:
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
lambda
表达式 直接使用 lambda 表达式:
list.sort((o1, o2) -> o1.compareTo(o2));
使用方法引用(方法引用具体概念和使用可以查看相关文章):
list.sort(Integer::compare);
可以明显看出,使用 lambda 表达式和方法引用极大提高了开发的速度,提升了代码的简洁性.
实际上, lambda 表达式只是JVM提供的语法糖。在JVM执行过程中,会根据 lambda 表达式的规则,动态创建出匿名的接口实现类对象.
lambda
表达式本质上是Java对象。 可以通过查看 lambda 表达式的 Class 对象和实例对象来证明这一点:
public class LambdaExpression {
public void printConsumer(Consumer consumer) {
System.out.println(consumer.getClass());
System.out.println(consumer.getClass().getInterfaces()[0]);
System.out.println(consumer);
}
}
运行以下代码:
LambdaExpression lambdaObjPrinter = new LambdaExpression();
lambdaObjPrinter.printConsumer(o -> o.getClass());
lambdaObjPrinter.printConsumer(o -> o.getClass());
会有如下输出:
class lambda.LambdaExpression$$Lambda$1/2003749087
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$1/2003749087@41629346
class lambda.LambdaExpression$$Lambda$2/1078694789
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$2/1078694789@6d311334
lambda
表达式动态生成函数式接口的实现类,并创建该实现类的实例。 lambda
表达式,尽管格式相同,仍然动态生成了2个实现类。 查看编译后的 .class 文件如下:
LambdaExpression lambdaObjPrinter = new LambdaExpression();
lambdaObjPrinter.printConsumer((o) -> {
o.getClass();
});
lambdaObjPrinter.printConsumer((o) -> {
o.getClass();
});
运行如下代码:
LambdaExpression lambdaObjPrinter = new LambdaExpression();
for (int i = 0; i < 2; i++) {
lambdaObjPrinter.printConsumer(o -> o.getClass());
}
System.out.println("=============");
for (int i = 0; i < 2; i++) {
lambdaObjPrinter.printConsumer(o -> o.getClass());
}
会发现有如下输出:
class lambda.LambdaExpression$$Lambda$1/2003749087
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$1/2003749087@41629346
class lambda.LambdaExpression$$Lambda$1/2003749087
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$1/2003749087@41629346
=============
class lambda.LambdaExpression$$Lambda$2/1078694789
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$2/1078694789@6d311334
class lambda.LambdaExpression$$Lambda$2/1078694789
interface java.util.function.Consumer
lambda.LambdaExpression$$Lambda$2/1078694789@6d311334
for
循环中( while
等循环结果相同),只会动态生成1个实现类。 查看编译后的 .class 文件如下:
LambdaExpression lambdaObjPrinter = new LambdaExpression();
int i;
for(i = 0; i < 2; ++i) {
lambdaObjPrinter.printConsumer((o) -> {
o.getClass();
});
}
System.out.println("=============");
for(i = 0; i < 2; ++i) {
lambdaObjPrinter.printConsumer((o) -> {
o.getClass();
});
}
lambda
表达式的优化。 lambda 表达式本质上是对函数式接口的匿名实现类实例的一种简化写法:方法格式和 lambda 表达式格式一一对应.
对于执行逻辑而言,方法主要由两部分组成(没有返回值):形参和方法体.
lambda 表达式与之对应: 1、形参: (t1, t2[, ……]) ,对应方法的形参 (T1 t1, T2 t2[, ……]) 2、箭头:->,固定 3、方法体:{},对应方法的方法体 。
根据方法形参和返回值的不同组合,lambda表达式可以分成以下几类:
() -> {
// 方法体
}
(t) -> {
// 方法体
}
多个形参:
(t1, t2[, ……]) -> { // 方法体 } 。
没有返回值:
() -> {
// 方法体
}
() -> {
// 方法体
return something;
}
根据形参个数的不同,形参部分可以有不同的写法: 1、没有形参或多个形参(超过1个),需要带 () :
() -> {
// 方法体
}
(t1, t2[, ……]) {
// 方法体
}
2、一个形参,可以省略 () :
(t) -> {
// 方法体
}
t -> {
// 方法体
}
根据方法体中代码行数的不同,方法体部分也有不同的写法: 1、一行代码,可以省略 {} (此时该行代码的 return 和 ; 也必须省略):
() -> {
System.out.println("Hello World!");
}
() -> System.out.println("Hello World!")
() -> {
return "Hello World!"
}
() -> "Hello World!"
2、多行代码,不可以省略 {} :
() -> {
System.out.println("Hello");
System.out.println("World!");
}
() -> {
System.out.println("Hello");
return "Hello World!"
}
lambda
表达式:
public class FunctionInterface {
interface AcceptEmpty {
void accept();
}
interface AcceptOne<T> {
void accept(T t);
}
interface AcceptMore<T, E> {
void accept(T t, E e);
}
interface ReturnVoid {
void returnVoid();
}
interface ReturnR<R> {
R returnR();
}
}
lambda
表达式:
/**
* 调用函数式接口的服务类
* @param <T> 第一个形参类型
* @param <E> 第二个形参类型
* @param <R> 返回值类型
*/
public class Service<T, E, R> {
private T t;
private E e;
public Service(T t, E e) {
this.t = t;
this.e = e;
}
void acceptEmpty(FunctionInterface.AcceptEmpty acceptEmpty) {
acceptEmpty.accept();
}
void acceptOne(FunctionInterface.AcceptOne<T> acceptOne) {
acceptOne.accept(this.t);
}
void acceptMore(FunctionInterface.AcceptMore<T, E> acceptMore) {
acceptMore.accept(this.t, this.e);
}
void returnVoid(FunctionInterface.ReturnVoid returnVoid) {
returnVoid.returnVoid();
}
R returnR(FunctionInterface.ReturnR<R> returnR) {
return returnR.returnR();
}
}
Service<Integer, Integer, String> service = new Service<>(1, 2);
service.acceptEmpty(new FunctionInterface.AcceptEmpty() {
@Override
public void accept() {
System.out.println("没有形参");
}
});
service.acceptEmpty(() -> {
System.out.println("没有形参");
});
service.acceptEmpty(() -> System.out.println("没有形参"));
service.acceptOne(new FunctionInterface.AcceptOne<Integer>() {
@Override
public void accept(Integer t) {
System.out.println(t);
}
});
service.acceptOne((t) -> System.out.println(t));
service.acceptOne(t -> System.out.println(t));
service.acceptMore(new FunctionInterface.AcceptMore<Integer, Integer>() {
@Override
public void accept(Integer t, Integer e) {
System.out.println(t);
System.out.println(e);
}
});
service.acceptMore((t, e) -> {
System.out.println(t);
System.out.println(e);
});
service.returnVoid(new FunctionInterface.ReturnVoid() {
@Override
public void returnVoid() {
System.out.println("没有返回值");
}
});
service.returnVoid(() -> System.out.println("没有返回值"));
service.returnR(new FunctionInterface.ReturnR<String>() {
@Override
public String returnR() {
return "3";
}
});
service.returnR(() -> "3");
lambda
表达式本质上是传递了一个动态生成的匿名对象,是一种假的函数式编程。 lambda 表达式形式上看起来很像是函数式编程:将一个函数当作形参传给方法.
实际上,lambda表达式只是Java的一个语法糖,它本质上仍然是一个普通的Java对象.
在执行的过程中,lambda表达式最终还是会被解析成匿名的接口实现类对象.
由于多态特性,在执行过程中,调用是外部传进来的实现类实例的代码.
在这个过程中,我们甚至可以将该匿名对象保存起来,便于后续多次调用.
public interface Lambda<T, R> {
R method(T t);
}
public class FakeFunctionalProgramming<T, R> {
private T t;
private Lambda<T, R> lambda;
public void setT(T t) {
this.t = t;
}
public void setLambda(Lambda<T, R> lambda) {
this.lambda = lambda;
}
public void doSomeThing() {
T t = before();
R r = lambda.method(t);
after(r);
}
public T before() {
return t;
}
public void after(R r) {
System.out.println(r);
}
}
FakeFunctionalProgramming<String, String> ffp = new FakeFunctionalProgramming<>();
ffp.setT("Xianhuii");
ffp.setLambda((t) -> "Hello " + t + "!");
ffp.doSomeThing(); // Hello Xianhuii!
从上述结果可以看出, lambda 表达式的编程方式本质上是利用了多态的特性,同时又使用了模板方法模式:
Lambda<T, R>
作为形参。 before()
方法,处理相对固定的前处理逻辑。 Lambda<T, R>
实例,进行特定处理。 Lambda<T, R>
特定处理后的返回值。 after()
方法,处理相对固定的后处理逻辑。 此时,我们应该能够透彻理解 lambda 表达式中 形参的来源 , 返回值的去向 了.
借助Java多态特性,以及JVM动态生成匿名实现类实例的功能, lambda 表达式才表现得那么像是函数式编程.
最后此篇关于Javalambda表达式基本使用的文章就讲到这里了,如果你想了解更多关于Javalambda表达式基本使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在用 yacc/bison 编写一个简单的计算器。 表达式的语法看起来有点像这样: expr : NUM | expr '+' expr { $$ = $1 + $3; } | expr '-'
我开始学习 lambda 表达式,并在以下情况下遇到了以下语句: interface MyNumber { double getValue(); } MyNumber number; nu
这两个 Linq 查询有什么区别: var result = ResultLists().Where( c=> c.code == "abc").FirstOrDefault(); // vs. va
如果我们查看 draft C++ standard 5.1.2 Lambda 表达式 段 2 说(强调我的 future ): The evaluation of a lambda-expressio
我使用的是 Mule 4.2.2 运行时、studio 7.5.1 和 Oracle JDK 1.8.0_251。 我在 java 代码中使用 Lambda 表达式,该表达式由 java Invoke
我是 XPath 的新手。我有网页的html源 http://london.craigslist.co.uk/com/1233708939.html 现在我想从上面的页面中提取以下数据 完整日期 电子
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我将如何编写一个 Cron 表达式以在每天上午 8 点和下午 3:30 触发?我了解如何创建每天触发一次的表达式,而不是在多个设定时间触发。提前致谢 最佳答案 你应该只使用两行。 0 8 * * *
这个问题已经有答案了: What do 3 dots next to a parameter type mean in Java? (9 个回答) varargs and the '...' argu
我是 python 新手,在阅读 BeautifulSoup 教程时,我不明白这个表达式“[x for x in titles if x.findChildren()][:-1]”我不明白?你能解释一
(?:) 这是一个有效的 ruby 正则表达式,谁能告诉我它是什么意思? 谢谢 最佳答案 正如其他人所说,它被用作正则表达式的非捕获语法,但是,它也是正则表达式之外的有效 ruby 语法。 在
这个问题在这里已经有了答案: Why does ++[[]][+[]]+[+[]] return the string "10"? (10 个答案) 关闭 8 年前。 谁能帮我处理这个 JavaSc
这个问题在这里已经有了答案: What is the "-->" operator in C++? (29 个答案) Java: Prefix/postfix of increment/decrem
这个问题在这里已经有了答案: List comprehension vs. lambda + filter (16 个答案) 关闭 10 个月前。 我不确定我是否需要 lambda 或其他东西。但是,
C 中的 assert() 函数工作原理对我来说就像一片黑暗的森林。根据这里的答案https://stackoverflow.com/a/1571360 ,您可以使用以下构造将自定义消息输出到您的断言
在this页,John Barnes 写道: If the conditional expression is the argument of a type conversion then effec
我必须创建一个调度程序,它必须每周从第一天上午 9 点到第二天晚上 11 点 59 分运行 2 天(星期四和星期五)。为此,我需要提供一个 cron 表达式。 0-0 0-0 9-23 ? * THU
我正在尝试编写一个 Linq 表达式来检查派生类中的属性,但该列表由来自基类的成员组成。下面的示例代码。以“var list”开头的 Process 方法的第二行无法编译,但我不确定应该使用什么语法来
此 sed 表达式将输入字符串转换为两行输出字符串。两条输出行中的每一行都由输入的子串组成。第一行需要转换成大写: s:random_stuff\(choice1\|choice2\){\([^}]*
我正在使用 Quartz.Net 在我的应用程序中安排我的工作。我只是想知道是否可以为以下场景构建 CRON 表达式: Every second between 2:15AM and 5:20AM 最
我是一名优秀的程序员,十分优秀!