Java8-新特性及Lambda表达式

news2025/7/19 1:33:44

1、Java8新特性内容概述

1.1、简介

Java 8(又称为jdk1.8)是Java语言开发的一个主要版本

Java 8是oracle公司于2014年3月发布,可以看成是自Java 5以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性

1.2、新特性思维导图总结

在这里插入图片描述

1.3、新特性好处

  • 速度更快
  • 代码更少==(增加了新的语法:lambda表达式)==
  • 强大的StreamAPI
  • 最大化减少空指针异常:Optional
  • Nashorn引擎,允许在JVM上运行JS应用

2、Lambda表达式概述

2.1、为什么使用

lambda是一个匿名函数,我们可以把lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提示。

2.2、语法

Lamdba表达式:在Java8语言中引入的一种新的语法元素和操作符。这个操作符为->,该操作符被称为Lambda操作符或箭头操作符。它将Lambda分为两个部分:

  • 左侧:指定了Lambda表达式需要的参数列表
  • 右侧:指定了Lambda体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能

举例:

(o1,o2) -> Integer.compare(o1,o2)

格式:

  • ->:lambda操作符 或 箭头操作符
  • 左边:lambda形参列表(其实就是接口中的抽象方法的形参列表)
  • 右边:lambda体(其实就是重写的抽象方法的方法体)

3、lambda表达式快速使用

大致分为6种情况讲解

  • 无参无返回值

    Runnable run = () -> {
        System.out.println(111);
    };
    
  • 需要一个参数,但没有返回值

    Consumer<String> con = (String x) -> {
        System.out.println(x);
    };
    
  • 数据类型可以省略,因为可由编译器推断出来,称为类型推断

    Consumer<String> con = (x) -> {
        System.out.println(x);
    };
    
  • 若只需要一个参数时,参数的小括号可以省略

    Consumer<String> con = str -> {
        System.out.println(str);
    };
    
  • 若需要两个以上的参数,多条执行语句,并且可以有返回值

    Comparator<Integer> con = (x,y) -> {
        System.out.println(x);
        System.out.println(y);
        return Integer.compare(x,y);
    };
    
  • 当Lambda体只有一条语句时,return与大括号若有,都可以省略

    Comparator<Integer> con = (x,y) -> Integer.compare(x,y);
    

无参无返回值

因为Runnable接口里的唯一接口方法run()方法就是无参无返回值的方法,所以我们可以使用Lambda表示

public static void main(String[] args){
    Runnable runn = () -> {
        System.out.println("hello world!");
    };

    runn.run(); //hello world!
}

需要一个参数,但没有返回值

Consumer接口里的唯一接口方法accept就是接收一个参数,无返回值的方法,所以可以使用Lambda表示

public static void main(String[] args){
    Consumer<String> con = (String s) ->{
        System.out.println(s);
    };
    con.accept("hello world!"); // hello world!
}

数据类型可以省略

//Java可以类型推断,前面定义泛型,后面参数就不可能是其他类型了,所以可以省略
Consumer<String> con = (s) ->{
    System.out.println(s);
};
con.accept("hello world!"); // hello world!

若只需要一个参数时,参数的小括号可以省略

// 因为我们只有一个参数 s,所以小括号也可以省略,只有在参数个数等于1的时候,才能省略,小于或者大于都不能省略!!!
Consumer con = s ->{
    System.out.println(s);
};
con.accept("hello world!"); // hello world!

若需要两个以上的参数,多条执行语句,并且可以有返回值

public static void main(String[] args){
    Comparator<Integer> com = (x,y) -> {
        System.out.println(x); // 1
        System.out.println(y); // 5
        return Integer.compare(x,y);
    };
    int i = com.compare(1, 5);
    System.out.println(i); // -1
}

当Lambda体只有一条语句时,return与大括号若有,都可以省略

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
int i = com.compare(1, 5);
System.out.println(i); // -1

4、函数式接口

4.1、如何理解函数式接口

  • Java从诞生起就一直倡导一切皆对象,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的星期和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即Java不但可以支持OOP还可以支持OOF(面向函数编程)
  • 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Labda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口
  • 简单的说,在java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示
  • 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写

4.2、什么是函数式(Function)接口

  • 只包含一个抽象方法的接口,成为函数式接口
  • 你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)
  • 我们可以在一个接口上使用==@FunctionalInterface==注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口
  • 在java.util.function包下定义了Java8的丰富的函数式接口

4.3、Java内置四大核心函数式接口

Java提供了四大核心函数式接口

  • Consumer:消费性接口。对类型为T的对象应用操作,包含方法:void accept(T t)
  • Supplier:供给型接口。返回类型为T的对象,包含方法:T get()
  • Function<T,R>:函数型接口。对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
  • Predicate:断定型接口。确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t)

在这里插入图片描述

Consumer

public static void main(String[] args){
    Consumer<String> con = s -> System.out.println(s);
    con.accept("hello world!"); // hello world!
}

Supplier

public static void main(String[] args){
    Supplier<String> sup = () -> "hello world";
    String s = sup.get();
    System.out.println(s); // hello world
}

Function<T,R>

public static void main(String[] args){
    // 输入类型为Integer类型,返回结果为String类型
    Function<Integer,String> fun = (a) -> String.valueOf(a);
    String apply = fun.apply(5201314);
    System.out.println(apply); // 5201314
}

Predicate

public static void main(String[] args){
    Predicate<String> pre = (s) -> s == null;
    boolean aaa = pre.test("aaa");
    System.out.println(aaa); // false

    boolean test = pre.test(null);
    System.out.println(test); // true
}

4.4、其他接口

除了上面四大核心接口外,还提供了针对四大核心接口的增强接口,有需要的可以直接使用

在这里插入图片描述

5、方法引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用

  • 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖

  • 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致

  • 如下三种主要使用情况

    • 对象::实例方法名

    • 类::静态方法名

    • 类::实例方法名

5.1、对象::实例方法名

// 情况一:对象::方法
// Consumer中的void accept(T t)
// PrintSteam中的void println(T t)
public static void main(String[] args){
    Consumer<String> con1 = a -> System.out.println(a);
    con1.accept("hello"); // hello

    System.out.println("*****************************");

    PrintStream out = System.out;
    // 对象::方法,结果和上面一样
    Consumer<String> con2  = out::println;
    con2.accept("world!"); // world
}

5.2、类::静态方法名

// 情况二:类::静态方法
// Comparator中的int compare(T o1, T o2)
// Integer中的static int compare(int x, int y)
public static void main(String[] args){
    Comparator<Integer> com = (x,y) -> x.compareTo(y);
    int i = com.compare(10, 20);
    System.out.println(i); // -1

    System.out.println("***************************");

    Comparator<Integer> com2 = Integer::compare;
    int i2 = com2.compare(10, 20);
    System.out.println(i2); // -1
}

5.3、类::实例方法名

// 情况二:类::实例方法
// Comparator中的int compare(T o1, T o2)
// Integer中的int compareTo(Integer anotherInteger)
// 虽然参数数量不一致,但是调用方法为这样结构的 o1.xxx(o2),可以写 o1的类名::o1要调用的方法
public static void main(String[] args){
    Comparator<Integer> com = (x,y) -> x.compareTo(y);
    int i = com.compare(10, 20);
    System.out.println(i); // -1

    System.out.println("***************************");

    Comparator<Integer> com2 = Integer::compareTo;
    int i2 = com2.compare(10, 20);
    System.out.println(i2); // -1
}

6、构造器引用

6.1、无参构造

public class Test{
    public static void main(String[] args){
        // Supplier<T>中的 T get()
        // Student中的 public Student() 无参构造
        Supplier<Student> sup = () -> new Student();
        System.out.println(sup.get()); // Student{name='null', age=null, birthday=null}

        // 构造引用写法
        Supplier<Student> sup2 = Student::new;
        System.out.println(sup2.get()); // Student{name='null', age=null, birthday=null}
    }
}

class Student{
    private String name;
    private Integer age;
    private LocalDateTime birthday;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }

    public Student() {
    }

    public Student(String name, Integer age, LocalDateTime birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
    
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name) {
        this.name = name;
    }
}

6.2、单参数构造

public class Test{
    public static void main(String[] args){
        // Function<T,R>中的 R apply(T t)
        // Student中的 public Student(String name) 单参构造
        Function<String,Student> fun = a -> new Student(a);
        Student apply = fun.apply("张三");
        System.out.println(apply); // Student{name='张三', age=null, birthday=null}

        // 构造引用写法
        Function<String,Student> fun2 = Student::new;
        Student apply1 = fun2.apply("李四");
        System.out.println(apply1); // Student{name='李四', age=null, birthday=null}
    }
}

//... 下面实体类省略

6.2、双参数构造

public class Test{
    public static void main(String[] args){
        // BiFunction<T,U,R>中的 R apply(T t, U u)
        // Student中的 public Student(String name, Integer age) 双参构造
        BiFunction<String,Integer,Student> biFun1 = (a,b) -> new Student(a,b);
        Student apply = biFun1.apply("张三", 20);
        System.out.println(apply); // Student{name='张三', age=20, birthday=null}

        // 构造引用写法
        BiFunction<String,Integer,Student> biFun2 = Student::new;
        Student apply2 = biFun2.apply("李四", 25);
        System.out.println(apply2); // Student{name='李四', age=25, birthday=null}
    }
}
//... 下面实体类省略

6.3、三参数构造

三参构造我们上面讲解Java的函数式接口并没有提到,我也不知道,所以需要自己写一个函数式接口,满足业务需求

1、定义函数式接口

@FunctionalInterface
interface MyFunction<T,U,O,R>{
    R apply(T t, U u, O o);
}

2、使用自定义函数式接口

public static void main(String[] args){
    // MyFunction<T,U,O,R>中的 R apply(T t, U u, O o)
    // Student中的 public Student(String name, Integer age, LocalDateTime birthday) 三参构造
    MyFunction<String,Integer,LocalDateTime,Student> mf = (a,b,c) -> new Student(a,b,c);
    Student apply = mf.apply("张三", 20, LocalDateTime.now());
    System.out.println(apply); // Student{name='张三', age=20, birthday=2022-11-25T16:01:10.610}

    // 构造引用写法
    MyFunction<String,Integer,LocalDateTime,Student> mf2 = Student::new;
    Student apply2 = mf.apply("李四", 25, LocalDateTime.now());
    System.out.println(apply2); // Student{name='李四', age=25, birthday=2022-11-25T16:01:10.611}
}

7、数组引用

就把数组当成特殊的类,使用new关键字创建

public static void main(String[] args){
    // MyFunction<T,U,O,R>中的 R apply(T t, U u, O o)
    // Student中的 public Student(String name, Integer age, LocalDateTime birthday) 三参构造
    Function<Integer,String[]> fun = length -> new String[length];
    String[] strings = fun.apply(3);
    for (String string : strings) {
        /*
                null
                null
                null
             */
        System.out.println(string);
    }

    System.out.println("**********************************************");

    // 数组引用
    Function<Integer,String[]> fun2 = String[]::new;
    String[] strings2 = fun2.apply(4);

    for (String s : strings2) {
        /*
                null
                null
                null
                null
             */
        System.out.println(s);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/37988.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS中数组随机排序实现(原地算法sort/shuffle算法)

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;专注于前端领域各种技术&#xff0c;热衷分享&#xff0c;期待你的关注。 &#x1f4ab;系列专栏&#xff1a;vue3从入门到精通 &#x1f4dd;个人签名&#xff1a;不破不立 目录一、原地…

代码随想录刷题|LeetCode 70. 爬楼梯(进阶) 322. 零钱兑换 279.完全平方数 139.单词拆分

目录 70. 爬楼梯 &#xff08;进阶&#xff09; 思路 爬楼梯 1或2步爬楼梯 多步爬楼梯 322. 零钱兑换 思考 1、确定dp数组及其含义 2、确定递推公式 3、初始化dp数组 4、确定遍历顺序 零钱兑换 先遍历物品&#xff0c;再遍历背包 先遍历背包&#xff0c;再遍历物品 279.完全平方…

【操作系统实验】线程的创建+信号量通信

sem_init: 功能&#xff1a;初始化信号量 返回值&#xff1a;创建成功返回0&#xff0c;失败返回-1 参数sem&#xff1a;指向信号量结构的一个指针 参数pshared&#xff1a;不为&#xff10;时此信号量在进程间共享&#xff0c;为0时当前进程的所有线程共享 参数value&#xf…

react context原理

带着问题思考&#xff1a; 1 Provder 如何传递 context&#xff1f;2 三种获取 context 原理 &#xff08; Consumer&#xff0c; useContext&#xff0c;contextType &#xff09;&#xff1f;3 消费 context 的组件&#xff0c;context 改变&#xff0c;为什么会订阅更新 &a…

Vue+iview将表格table以excel文件导出的几种方式

前言 在日常工作中&#xff0c;若是经常跟后台管理系统打交道的朋友想必对导出excel表格这种需求肯定很熟悉吧。不过我也问了身边的一些岗位为后端工程师的朋友&#xff0c;他们说在公司的话一般导出excel表格的工作一般由后端来做&#xff0c;前端只需要调用接口即可。我的话…

AI面试必备-《家居必备的AI精选资源列表》免费分享

本资源介绍 DeepMind科学家和工程师为有兴趣了解更多人工智能、机器学习和其他相关主题的学生整理的教育资源列表。 文末附本书免费获取地址。 内容截图 本资源免费下载地址 链接: https://pan.baidu.com/s/1IkPk0a3q2Z1z4FATG2y7HA?pwdwy3c 提取码: wy3c 往期精品内容推荐 大…

认知电子战 | 无线电中的认知理论

认知的概念 认知(Cognition)是指人认识外界事务的过程 认知本来是用于描述具有生命特征的物种的,借用于机器或系统上,就是指将认知的思想应用于机器上。 生物的认知特点: 感觉思考、推理、问题解答判断记忆分别对应于系统认知特点: 感知(各种传感器)机器学习算法、基…

算法提升:图的启发式搜索算法(A算法、A*算法)

启发式搜索算法 目录 概念 A算法 A*算法 概念 启发式搜索(Heuristically Search)又称为有信息搜索(Informed Search)&#xff0c;它是利用问题拥有的启发信息来引导搜索&#xff0c;达到减少搜索范围、降低问题复杂度的目的&#xff0c;这种利用启发信息的搜索过程称为启发…

修改 Git 已经提交记录的 用户名 和邮箱

修改 Git 已经提交记录的 用户名 和邮箱 有关 Git 和版本控制的常见问题。 如何更改提交的作者姓名/电子邮件&#xff1f; 在我们进入解决方案之前&#xff0c;让我们找出您到底想要完成什么&#xff1a; 在提交之前更改作者信息在提交后更改作者信息&#xff08;即历史提交…

常见的前端安全问题(xss / csrf / sql / ddos / cdn...)

目录 1. xss&#xff08;Cross Site Scripting&#xff09;跨站脚本攻击 1.1 持久型&#xff08;存储型&#xff09;攻击 / 非持久型&#xff08;反射型&#xff09;攻击 是什么&#xff1f; 1.2 xss 出现的场景&#xff1f;造成的危害&#xff1f; 1.3 防御 xss&#xff0…

three.js之Geometry顶点、颜色数据与三角面

文章目录简介顶点对于代码的解释颜色对于代码的解释三角面专栏目录请点击 简介 Geometry与BufferGeometry表达的含义相同&#xff0c;只是对象的结构不同three.js渲染的时候会先把Geometry转化为BufferGeometry在解析几何体顶点数据进行渲染 顶点 <!DOCTYPE html> <…

基于JavaWeb的药品进销存管理系统(JSP)

目 录 绪论 1 1.1 本课题的研究背景 1 1.2 国内外研究现状 1 1.3 本课题的主要工作 2 1.4 目的和意义 2 开发工具及技术 3 2.1 开发工具 3 2.1.1 MyEclipse 3 2.1.2 Tomcat 3 2.1.3 Mysql 3 2.2 开发技术 4 2.2.1 JSP 4 2.2.2 MyBatis 4 2.2.3 JavaScript 4 2.2.4 jQuery以及j…

机械原理-试题及答案

模拟试题八&#xff08;机械原理A&#xff09; 一、判断题&#xff08;10分&#xff09;[对者画√&#xff0c;错者画 ] 1、对心曲柄滑块机构都具有急回特性。&#xff08; &#xff09; 2、渐开线直齿圆柱齿轮的分度圆与节圆相等。&#xff08; &#xff09; 3、当两直齿圆柱齿…

Spring Cloud OpenFeign - 日志配置

项目源码地址&#xff1a;https://download.csdn.net/download/weixin_42950079/87168704 OpenFeign 有 4 种日志级别&#xff1a; NONE: 不记录任何日志&#xff0c;是OpenFeign默认日志级别&#xff08;性能最佳&#xff0c;适用于生产环境&#xff09;。BASIC: 仅记录请求方…

[附源码]计算机毕业设计JAVA人力资源管理系统论文2022

[附源码]计算机毕业设计JAVA人力资源管理系统论文2022 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM…

QT对象树和菜单操作

前言 可以与MFC框架进行比较&#xff0c;总结彼此的相同点和不同点&#xff0c;在此基础上再去学习其他的界面框架&#xff0c;达到增量学习的境界。 一.对象树 优点&#xff1a;当父对象被析构时&#xff0c;如果子对象没有被析构&#xff0c;QT的对象树机制会去析构它&…

pandas索引操作、赋值操作、排序以及Series排序和DataFrame排序

一、pandas索引操作 索引操作&#xff0c;使用索引选取序列和切片选择数据&#xff0c;也可以直接使用列名、行名称&#xff0c;或组合使用 直接使用行列索引&#xff1a;行列索引名顺序为先列再行&#xff0c;使用指定行列索引名&#xff0c;不能使用下标loc[行索引名&#…

MySQL数据库表空间回收问题

MySQL数据库表空间回收问题1. MySQL表空间回收2. MySQL表空间设置3. MySQL删除数据流程4. MySQL数据页空洞问题1. MySQL表空间回收 我们经常会发现一个问题&#xff0c;就是把表数据删除以后发现&#xff0c;数据文件大小并没有变化&#xff0c;这就是标题中所说的MySQL数据库…

Numpy数组中的维度和轴

维度究竟是行数还是列数&#xff1f; m维行向量&#xff1a;m维表示一行中有m列&#xff0c;由于是行向量&#xff0c;所以是1行m列n维列向量&#xff1a;n维表示一行中有n行&#xff0c;由于是列向量&#xff0c;所以是n行1列m维向量&#xff1a;看书的习惯了&#xff0c;一般…

APS生产计划排产 — 排产结果拉动模具工装需求计划

APS生产计划排产系统&#xff0c;对所有资源具有同步的&#xff0c;实时的&#xff0c;具有约束能力的&#xff0c;模拟能力&#xff0c;不论是物料&#xff0c;机器设备&#xff0c;人员&#xff0c;供应&#xff0c;客户需求&#xff0c;运输等影响计划因素。不论是长期的或短…