JDK 1.8 LAMBADA表达式

简介: JDK 1.8 LAMBADA表达式

Lambad 表达式资料参考



简介:


现在的工作当中对于jdk1.8的lambada表达式使用越来越频繁,但是对于内部的一些细节却不是特别的清楚

这里借鉴了几篇博客,对比了之后对于博客到推荐进行了排序,同时也整理了这几篇博客提到的个人觉得比较重要到部分进行了验证


第一篇


objcoding.com/2019/03/04/… 一篇博客,介绍的比较到位,虽然文章很长但是通篇看完完全没有想点右上角的冲动


第二篇


juejin.cn/post/684490…

关于lambada的十个案例


重点部分:


Q:如何在lambda表达式中加入谓词?


A:解答


首先代码如下,按照个人理解,其实本质就是把用户的操作“拼接”,包括筛选,合并等操作,依赖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)); 
复制代码


第三篇


segmentfault.com/a/119000000…

关于lambada的一个详解

版权声明:本文由吴仙杰创作整理,转载请注明出处:segmentfault.com/a/119000000…


第四篇


www.oracle.com/webfolder/t…

Oracale官方案例

blog.csdn.net/renfufei/ar…

比较久远到一个文章,更多是批判的角度看待lambada


概览


  1. 介绍了stream 的基本概念
  1. 简写的依据 - 函数接口 和类型推断机制
  1. 函数式编程和匿名内部类的区别
  1. 使用上区别
  2. JVM上的本质区别
  1. JDK8 对于容器到扩展方法,其中部分是为了配合函数式编程而出现的
  1. Collections
  2. Map
  1. Stream API 介绍stream 的常用方法以及基本特性
  1. sort()

  1. stream内部实现的简单了解
  1. 用户的操作如何记录?
  2. 操作如何叠加?
  3. 叠加之后的操作如何执行?
  4. 执行后的结果(如果有)在哪里?


重点部分


Q:匿名内部类和lambada表达式的关键区别


A 回答


this的指向对象


  • 匿名内部类:this 指向的是匿名内部类的所属对象
  • lambada:this 指向当前运行的类,也就是当前运行的对象


jvm层面


  • 匿名内部类:会生成一个 $1到匿名内部类的对象,使用new指令生成对象并且执行
  • lambada:会生成一个私有方法,使用invokedynamic指令调用

匿名内部类的编译过程

为了更好到理解,自己做了一个实验

  1. 创建一个基本的匿名内部类到方法


网络异常,图片无法展示
|


代码如下:


/**
     * 匿名内部类和lambada的区别
     */
    @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);
    }
复制代码


  1. 查看classes ,可以看到编译后的class 文件如下,看到明显多出来一个LambadaTest1$1.class 这事啥东西?


网络异常,图片无法展示
|


  1. 打开cmd 使用cd 命令移动到改目录下面

小技巧1:

编译后到classes 如果想要直接查看class 文件的反编译到内容,可以直接把class 文件拖拽到 idea 里面进行打开,就可以看到class 到反编译内容~~~

  1. 反编译的内容如下,可以看到匿名内部类的编译后的内容经过解释之后,实际上是创建了一个匿名内部类的对象


网络异常,图片无法展示
|


  1. 在第一步的基础上,我们除了打印线程的名称,还可以打印this 看一下匿名内部类的this 是啥东西,我打印之后得到到匿名内部类的 this 如下: com.jdk.lambada.LambadaTest1$1@2fd014c6


小技巧2:

如何使用javap 查看java的汇编指令呢?

以上面到案例为例:

  1. 打开cmd,进入对应的class目录,我们可以执行javap <options> <classes>的格式进行翻译操作
  2. 执行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>    覆盖引导类文件的位置
复制代码


  1. 为了更进一步了解底层的jvm指令执行,使用javap -c -l -p xxx反编译结果如下


Compiled from "LambadaTest1.java"
public class com.jdk.lambada.LambadaTest1 {
  public com.jdk.lambada.LambadaTest1();
    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/lambada/LambadaTest1;
  public void test1() throws java.lang.InterruptedException;
    Code:
       0: new           #2                  // class java/lang/Thread
       3: dup
       4: new           #3                  // class com/jdk/lambada/LambadaTest1$1
       7: dup
       8: aload_0
       9: invokespecial #4                  // Method com/jdk/lambada/LambadaTest1$1."<init>":(Lcom/jdk/lambada/LambadaTest1;)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/lambada/LambadaTest1;
}
复制代码


可以发现,匿名内部类使用了 new到指令来实现匿名对象的生成,调用invokespecial执行内部的run方法

接下来我们看下Lambada简写上面的匿名内部类代码

lambada表达式编译过程


  1. 和上面的流程类似,这里直接略过一些不必要的点,代码如下


import java.util.concurrent.TimeUnit;
/**
 * @program: lambada
 * @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);
    }
}
复制代码


  1. 同样的,我们先把class文件放到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);
    }
}
复制代码


  1. 打开class所在目录,我们会发现lambada并没有像匿名内部类一样创建了一个$1 的对象,那么他是如何实现的?
  2. 我们使用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
}
复制代码


对比匿名内部类和lambada表达式可以明显发现,Lambada的不同在于使用了私有方法 加上 invokedynamic指令进行编译,而不会产生一个匿名内部类的对象class文件。

  1. 我们可以看下Lambada的 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("lambada this is = " + this);
        }).start();
        TimeUnit.SECONDS.sleep(5L);
    }
复制代码


这里惊讶的发现,编译居然无法通过!!!!

我们再对比使用匿名内部类的方式:


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);
}
复制代码


此方式可以正常编译通过并且运行,由此我们可以发现lambada的this 和匿名内部类的 this有着本质的区别


  1. 我们无法使用正常到方式打印this, 我们换一种方式,这里稍微调整代码,最后的代码如下:


/**
 * @program: lambada
 * @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: lambada表达式学习1
 * @author: zhaoxudong
 * @create: 2020-05-05 10:29
 **/
public class LambadaTest1 {
    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 "LambadaTest1{}";
    }
}
复制代码


结论:

匿名内部类:this 指向的是匿名内部类的所属对象(也就是Runnable

lambada:this 指向当前运行的类(也就是Test),也就是当前运行的对象


Q:Java8里面的java.util.Spliterator接口有什么用?


A:参考博客


思否

一句话概括:为了多线程并行遍历元素而设计到迭代器

版本:JDK1.8

目的:简化复杂到并行迭代程序编写

参考:Java7的Fork/Join(分支/合并)框架

CSDN上面到解答

JAVA8 stream 中Spliterator的使用(一)

JAVA8 stream 中Spliterator的使用(二)

相关文章
|
JavaScript 前端开发
【曹操】echarts图例legend选中状态动态设置
曹操项目语音质量分析功能前端页面展示,需要对所有指标的图例默认选中状态只显示前两个,其他指标的图例状态默认为灰色。
4850 0
|
前端开发 搜索推荐 JavaScript
使用uniapp实现时钟功能
使用uniapp实现时钟功能
543 1
|
JavaScript
搭建Vue3组件库:第四章 使用Vitepress搭建文档网站
文档建设一般会是一个静态网站的形式 ,这次采用 Vitepress 完成文档建设工作。 Vitepress 是一款基于Vite 的静态站点生成工具。开发的初衷就是为了建设 Vue 的文档。Vitepress 的方便之处在于,可以使用流行的 Markdown 语法进行编写,也可以直接运行 Vue 的代码。也就是说,它能很方便地完成展示组件 Demo 的任务。
2079 0
搭建Vue3组件库:第四章 使用Vitepress搭建文档网站
|
4月前
|
存储 Ubuntu 安全
在Ubuntu 16.04上安装openjdk-6/7/8-jdk的步骤
在整个安装过程中,你可能需要管理员权限,因此你可能要使用 `sudo` 来获取必要的权限。记得做完每一个步骤后,都要检查输出,以确保没有发生错误,并且每项操作都成功完成。如果在安装过程中遇到问题,查看 `/var/log/` 下的日志文件对于问题的解决可能是有帮助的。
321 21
|
JSON 前端开发 JavaScript
前端上传文件前校验文件数据
该文介绍了如何在Vue项目中实现批量导入Excel数据的校验。使用Element UI的`el-upload`组件上传文件,通过FileReader读取内容,结合XLSX库解析Excel为JSON。解析过程包括将二进制数据转换为workbook对象,提取worksheet并转化为JSON。之后,遍历JSON数据进行字段校验,若发现空值则记录错误。提供的Demo展示了选择Excel文件后控制台显示校验结果。技术栈包括vue 2.6.14、element ui 2.15.14和xlsx 0.17.0。建议将此类功能封装为通用组件以复用。
499 2
前端上传文件前校验文件数据
|
搜索推荐 算法 API
向量数据库-Milvus
Milvus 是一个开源的、高性能的向量数据库,专为海量向量数据的快速检索而设计。在人工智能、计算机视觉、推荐系统和其他需要处理大规模向量数据的领域有着广泛应用【7月更文挑战第3天】
2230 7
|
开发框架 前端开发 JavaScript
在Bootstrap开发框架基础上增加WebApi+Vue&Element的前端
在Bootstrap开发框架基础上增加WebApi+Vue&Element的前端
Compass Arena: 司南x魔搭携手推出大模型竞技场
从Llama-3的问世,到参数规模空前的MoE模型,再到GPT-4o的震撼发布,大语言模型(LLM)的飞速进步让人目不暇接。然而,随着模型数量的增加,如何客观、公正地评估和比较这些模型的性能,亟待探索与解决的问题。
|
文件存储
一篇文章讲明白LTE中的各种ID含义
一篇文章讲明白LTE中的各种ID含义
884 0
|
机器学习/深度学习 算法 数据可视化
YOLO+混合注意力机制 | YOLOv5再加4.3%才可以做对手,Transformer混合设计依旧可以卷
YOLO+混合注意力机制 | YOLOv5再加4.3%才可以做对手,Transformer混合设计依旧可以卷
496 0