#java
现在的工作中JDK 8的Lambda表达式基本是需要必备的技能。本文是一篇有关Lambda 表达式的文章和优质资料整理。
https://objcoding.com/2019/03/04/lambda/
一篇博客,介绍的比较到位,虽然文章很长但是通篇看完完全没有想点右上角的冲动。
此外,目录结构非常清晰。
https://juejin.im/post/5abc9ccc6fb9a028d6643eea
关于Lambda的十个案例。
如何在lambda表达式中加入谓词?
代码如下,其实本质就是把用户的操作“拼接”,包括筛选,合并等操作,依赖java.util.function.Predicate
此接口实现。
// 甚至可以用and()、or()逻辑函数来合并Predicate,
// 例如要找到所有以J开始,长度为四个字母的名字,你可以合并两个Predicate并传入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
.filter(startsWithJ.and(fourLetterLong))
.forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
https://segmentfault.com/a/1190000009186509
关于Lambda的一个详解。
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
虽然做的非常简陋,但是确实是最快的上手案例。
https://blog.csdn.net/renfufei/article/details/24600507
比较久远的一个文章,更多是批判的角度看待Lambda,分析的挺有意思的。
译者认为: 超过3行的逻辑就不适用Lambda表达式了。虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
本人建议不要乱用,因为这就和某些很高级的黑客写的代码一样,简洁,难懂,难以调试,维护人员想骂娘.)
匿名内部类:this
指向的是匿名内部类的所属对象(也就是Runnable)
Lambda:this
指向当前运行的类(也就是Test),也就是当前运行的对象
this的指向对象
this
指向的是匿名内部类的所属对象this
指向当前运行的类,也就是当前运行的对象jvm层面
$1
到匿名内部类的对象,使用new
指令生成对象并且执行invokedynamic
指令调用重点部分在匿名内部类的编译过程。为了更好到理解,自己做了一个实验 。
代码如下:
/**
* 匿名内部类和Lambda的区别
*/
@Test
public void test1() throws InterruptedException {
new Thread(new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
System.err.println(name + " is run as a thread ");
}
}).start();
Thread.sleep(2000);
}
LambdaTest1$1.class
。cmd
使用cd
命令移动到对应目录下面。或者使用Idea 快速打开对应目录小技巧 1:
编译后到 classes,如果想要直接查看 class 文件的反编译内容,可以直接把 class 文件拖拽到 idea 里面进行打开,就可以看到 class 到反编译内容~~~
this
看一下匿名内部类的this 是啥东西</font>。个人打印之后得到到匿名内部类的 this 如下: com.jdk.Lambda.LambdaTest1$1@2fd014c6
小技巧 2:
如何使用javap 查看java的汇编指令呢?
以上面到案例为例:
打开
cmd
,进入对应的class目录,我们可以执行javap <options> <classes>
的格式进行翻译操作 执行javap -c -l -p xxx
,得到结果:选项的含义?
-help --help -? 输出此用法消息 -version 版本信息,其实是当前javap所在jdk的版本信息,不是class在哪个jdk下生成的。 -v -verbose 输出附加信息(包括行号、本地变量表,反汇编等详细信息) -l 输出行号和本地变量表 -public 仅显示公共类和成员 -protected 显示受保护的/公共类和成员 -package 显示程序包/受保护的/公共类 和成员 (默认) -p -private 显示所有类和成员 -c 对代码进行反汇编 -s 输出内部类型签名 -sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列) -constants 显示静态最终常量 -classpath < path > 指定查找用户类文件的位置 -bootclasspath < path > 覆盖引导类文件的位置
javap -c -l -p xxx
反编译结果如下Compiled from "LambdaTest1.java"
public class com.jdk.Lambda.LambdaTest1 {
public com.jdk.Lambda.LambdaTest1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 11: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jdk/Lambda/LambdaTest1;
public void test1() throws java.lang.InterruptedException;
Code:
0: new #2 // class java/lang/Thread
3: dup
4: new #3 // class com/jdk/Lambda/LambdaTest1$1
7: dup
8: aload_0
9: invokespecial #4 // Method com/jdk/Lambda/LambdaTest1$1."<init>":(Lcom/jdk/Lambda/LambdaTest1;)V
12: invokespecial #5 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
15: invokevirtual #6 // Method java/lang/Thread.start:()V
18: ldc2_w #7 // long 2000l
21: invokestatic #9 // Method java/lang/Thread.sleep:(J)V
24: return
LineNumberTable:
line 19: 0
line 24: 15
line 25: 18
line 27: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 this Lcom/jdk/Lambda/LambdaTest1;
}
可以发现,匿名内部类使用了 new
到指令来实现生成匿名对象,调用invokespecial
执行内部的run
方法
接下来我们使用Lambda简写上面的匿名内部类代码。
import java.util.concurrent.TimeUnit;
/**
* @program: Lambda
* @description: 测试jdk1.8
* @author: zhaoxudong
* @create: 2020-05-05 11:42
**/
public class Test {
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
System.err.println(" test" + Thread.currentThread().getName() + " is run as a thread " );
}).start();
TimeUnit.SECONDS.sleep(5L);
}
}
idea
下面,查看反编译之后的代码//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.util.concurrent.TimeUnit;
public class Test {
public Test() {
}
public static void main(String[] args) throws InterruptedException {
(new Thread(() -> {
System.err.println(" test" + Thread.currentThread().getName() + " is run as a thread ");
})).start();
TimeUnit.SECONDS.sleep(5L);
}
}
javap -c -l -p xxx
翻译 class, 得到结果如下:public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LTest;
public static void main(java.lang.String[]) throws java.lang.InterruptedException;
Code:
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run: ()Ljava/lang/Runnable;
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: invokevirtual #5 // Method java/lang/Thread.start:()V
15: getstatic #6 // Field java/util/concurrent/TimeUnit.SECONDS:Ljava/util/concurrent/TimeUnit;
18: ldc2_w #7 // long 5l
21: invokevirtual #9 // Method java/util/concurrent/TimeUnit.sleep:(J)V
24: return
LineNumberTable:
line 12: 0
line 14: 12
line 15: 15
line 16: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 args [Ljava/lang/String;
private static void lambda$main$0();
Code:
0: getstatic #10 // Field java/lang/System.err:Ljava/io/PrintStream;
3: new #11 // class java/lang/StringBuilder
6: dup
7: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V
10: ldc #13 // String test
12: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokestatic #15 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
18: invokevirtual #16 // Method java/lang/Thread.getName:()Ljava/lang/String;
21: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: ldc #17 // String is run as a thread
26: invokevirtual #14 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #18 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: invokevirtual #19 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: return
LineNumberTable:
line 13: 0
line 14: 35
}
对比匿名内部类和Lambda表达式,可以发现Lambda的不同在于使用了私有方法
加上 invokedynamic
指令进行编译,而不会产生一个匿名内部类的对象class文件。
this
打印的是什么东西public static void main(String[] args) throws InterruptedException {
new Thread(()->{
System.err.println(" test" + Thread.currentThread().getName() + " is run as a thread " );
System.err.println("Lambda this is = " + this);
}).start();
TimeUnit.SECONDS.sleep(5L);
}
这里惊讶的发现,编译居然无法通过!!!! 我们再对比使用匿名内部类的方式:
这种验证方式也可以证明 <font color='red'>Lambda的 this 和匿名内部类的 this 有着本质的区别</font>。
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
System.err.println(name + " is run as a thread " + this);
}
}).start();
Thread.sleep(2000);
}
最终代码如下:
/**
* @program: Lambda
* @description: 测试jdk1.8
* @author: zhaoxudong
* @create: 2020-05-05 11:42
**/
public class Test {
Runnable run = () ->{
System.err.println(this);
};
public static void main(String[] args) throws InterruptedException {
new Thread(new Test().run).start();
TimeUnit.SECONDS.sleep(5L);
}
@Override
public String toString() {
return "test";
}
}
执行上面的代码,可以得到结果test
在匿名内部类如何得到结果呢?
可以看下面的代码,结果依然是打印
test
/**
* @program: smartframwork
* @description: Lambda表达式学习1
* @author: zhaoxudong
* @create: 2020-05-05 10:29
**/
public class LambdaTest1 {
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
System.err.println(name + " is run as a thread " + this);
}
@Override
public String toString() {
return "test";
}
}).start();
Thread.sleep(2000);
}
@Override
public String toString() {
return "LambdaTest1{}";
}
}
参考博客:Java8里面的java.util.Spliterator接口有什么用?
一句话概括:为了多线程并行遍历元素而设计到迭代器
版本:JDK 8
目的:简化复杂到并行迭代程序编写。
参考:Java7 的Fork/Join
(分支/合并)框架。
其他参考资料:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。