Java8中Lambda表达式和方法引用

news2024/11/16 22:00:02

一、Lambda表达式

1.1 函数式编程思想

1)概念

​ 面向对象思想需要关注用什么对象完成什么事情。而函数式编程思想就类似于我们数学中的函数。它主要关注的是对数据进行了什么操作。

2)优点

  • 代码简洁,开发快速
  • 接近自然语言,易于理解
  • 易于"并发编程"

1.2 Lambda表达式基础

1)概述

LambdaJDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。

它是函数式编程思想的一个重要体现。

让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。

2)核心原则

可推导可省略。

需要是函数式接口,既只有一个方法的接口。

3)基本格式

  • 由三部分组成:
    • 一些参数
    • 一个箭头
    • 一段代码
  • 格式:
(参数列表)->{重写方法的代码}
  • 解释说明格式:
    • (): 接口中抽象方法的参数列表,没有参数就空着,有参数就写出参数,多个参数使用逗号分隔
    • -> : 就是传递的意思。即把参数传递给方法体{}
    • {} : 重写接口的抽象方法的方法体

1.3 示例

  • 创建并启动线程
// 在创建线程并启动时可以使用匿名内部类的写法:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("hello!");
    }
}).start();

// ------------------------------分隔线-----------------------------
// 使用Lambda的格式对其进行修改 
new Thread(()->{
    System.out.println("hello!");
}).start();
  • 函数式接口作为参数

    现有方法定义如下,其中IntBinaryOperator是一个函数式接口。

// 先使用匿名内部类的写法调用该方法
public static int calculateNum(IntBinaryOperator operator){
    int a = 10;
    int b = 20;
    return operator.applyAsInt(a, b);
}

public static void main(String[] args) {
    int i = calculateNum(new IntBinaryOperator() {
        @Override
        public int applyAsInt(int left, int right) {
            return left + right;
        }
    });
    System.out.println(i);
}

// ------------------------------分隔线-----------------------------
// 使用Lambda的格式对其进行修改 
public static void main(String[] args) {
    int i = calculateNum((int left, int right)->{
        return left + right;
    });
    System.out.println(i);
}

1.4 省略规则

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略

这些规则不需要死记硬背

1.5 使用规则

函数式接口,或者只有一个抽象方法的匿名内部类才可以转换为Lambda表达式。

二、函数式接口

2.1 概述

只有一个抽象方法的接口我们称之为函数接口。

JDK自带的函数式接口都加上了**@FunctionalInterface** 注解进行标识。

但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。

2.2 常见JDK自带的函数式接口

1)Supplier 生产者接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回。
在这里插入图片描述

使用示例:

/*
  java.util.function.supplier<T>接口仅包含一个无参方法T.get()用来获取一个泛型参数指定类型的对象数据
  suppier<T> 接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据
 */
public class Demo01Supplier {

    //定义一个方法,方法的参数传递supplier<T>接口,泛型执行String.get方法就会返回一个String
    public  static  String getString(Supplier<String> sup){
        return  sup.get();
    }

    public static void main(String[] args) {
        //调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递一个Lambda表达式
        String str = getString(() -> {
            return "小萌新";
        });
        System.out.println(str);
    }

}

2)Consumer消费接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。
在这里插入图片描述

使用示例:

// consumer接口是一个消费型的接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据
public class DemoConsumer {

    public static void consumerString(String name, Consumer<String> consumer){
        //accept方法并没有返回值
        consumer.accept(name);
    }

    public static void main(String[] args) {
        consumerString("噜啦噜啦嘞", (String name)->{
            //消费方式,直接输出字符串
            System.out.println(name);
            //消费方式,反转输出字符串
            String newName = new StringBuilder(name).reverse().toString();
            System.out.println(newName);
        });
    }
}

3)Function 计算转换接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回
在这里插入图片描述

使用示例:

public class DemoFunction {

    /*
        定义一个方法
        方法的参数传递一个字符串类型的整数
        方法的参数传递Function接口,泛型使用<String,Integer>
        使用Function 接口中的方法apply,把字符串类型的整数,转换为Integer类型的整数
     */

    public  static  void  change(String s,Function<String,Integer> function){
        //把泛型左边的类型转换成右边
        Integer in = function.apply(s);
        System.out.println(in);
    }

    public static void main(String[] args) {
        change("1234",(String s)->{
            return  Integer.valueOf(s) + 1;
        });
    }

}

4)Predicate 判断型接口

在这里插入图片描述

使用示例:

  • 基础用法
public class DemoPredicate {

    /*
        定义一个方法
        参数传递一个String 类型的字符串
        传递一个predicate接口,泛型使用String
        使用Predicate中的方法test对字符串进行判断,并把判断的结果返回

     */
    public static boolean checkString(String  s, Predicate<String> predicate){
        return  predicate.test(s);
    }

    public static void main(String[] args) {
        String s = "asd";
        boolean result = checkString(s,(String str)->{
            return  str.length() > 5;
        });
        System.out.println(result);
    }

}

  • Predicate接口中有一个方法and 表示并且关系,也可用于连接两个判断条件
public class DemoPredicateAnd {

    // 定义一个方法 传递一个字符串和两个Predicate接口
    public  static boolean checkString(String s, Predicate<String> predicate1, Predicate<String> predicate2){
        return predicate1.and(predicate2).test(s);
    }

    public static void main(String[] args) {
        String s = "sdfgg";
        boolean a = checkString(s,
                (String str) -> {
                    return str.length() > 5;
                }, (String str) -> {
                    return str.contains("a");
                });
        System.out.println(a);
    }
}
  • and 的与类似,默认方法or实现逻辑关系中的或
public class DemoPredicateOr {

    private static void method(Predicate<String> one, Predicate<String> two) {
        boolean isValid = one.or(two).test("Helloworld");
        System.out.println("字符串符合要求吗:" + isValid);
    }
    public static void main(String[] args) {
        method(s -> s.contains("H"), s -> s.contains("W"));
    }


}
  • negate方法相当于是在判断添加前面加了个! 表示取反
public class DemoPredicateNegate {

    private static void method(Predicate<String> predicate) {
        boolean veryLong = predicate.negate().test("HelloWorld");
        System.out.println("字符串很长吗:" + veryLong);
    }

    public static void main(String[] args) {
        method(s -> s.length() < 5);
    }

}

三、方法引用

在使用Lambda表达式时,如果方法体中只有一个方法的调用的话(包括构造方法)时,我们可以用方法引用进一步简化代码。

6.1 小技巧

在使用Lambda表达式时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。

只需要在写完Lambda表达式时发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方

法引用即可。

当我们方法引用使用的多了慢慢的也可以直接写出方法引用。

6.2 基本格式

类名或者对象名::方法名

6.3 语法详解

6.3.1 引用类的静态方法

其实就是引用类的静态方法

1)格式:
类名::方法名
2)使用前提:

如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法

并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态

方法。

3)示例:

如下代码就可以用方法引用进行简化

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.map(author -> author.getAge()).map(age->String.valueOf(age));

注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。

4)使用方法引用优化:
List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.map(author -> author.getAge()).map(String::valueOf);

6.3.2 引用对象的实例方法

1)格式:
对象名::方法名
2)使用前提:

如果在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且把要重写的

抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法。

3)示例:
List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(name->sb.append(name));
4)使用方法引用优化:
List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(sb::append);

6.3.4 引用类的实例方法

1)格式:
类名::方法名
2)使用前提:

如果在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要

重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。

3)示例:
// 函数式接口
interface UseString{
    String use(String str,int start,int length);
}
// 使用函数式接口作为参数,因此可以使用lambda表达式进行参数传递
public static String subAuthorName(String str, UseString useString){
    int start = 0;
    int length = 1;
    return useString.use(str, start, length);
}

public static void main(String[] args) {
    subAuthorName("张三", new UseString() {
        @Override
        public String use(String str, int start, int length) {
            return str.substring(start, length);
        }
    });
}
4)使用方法引用优化:
public static void main(String[] args) {
    subAuthorName("张三", String::substring);
}

6.3.5 构造器引用

如果方法体中的一行代码是构造器的话就可以使用构造器引用。

1)格式:
类名::new
2)使用前提:

如果在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把

要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。

3)示例:
List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(name->new StringBuilder(name))
    .map(sb->sb.append("test").toString())
    .forEach(str-> System.out.println(str));
4)使用方法引用优化:
List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(StringBuilder::new)
    .map(sb->sb.append("test").toString())
    .forEach(str-> System.out.println(str));

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

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

相关文章

1-n范围内的质数查找:埃拉托斯特尼筛法

文章目录 质数查找思路质数定义代码思路 写法重要逻辑&#xff1a;第一层for循环结束条件是i * i < n而不是i<n第二层循环如何筛查i所有倍数 完整版&#xff1a;返回0-n正整数中所有质数时间复杂度例题参考资料&#xff1a; 质数查找思路 质数定义 质数是一个自然数&am…

操作系统之调度算法总结

目录 一、进度调度算法 二、内存调度算法 一、先来先服务调度算法 二、最短寻道时间优先调度算法 三、扫描算法 四、循环扫描算法 五、LOOK和C-LOOK算法 三、内存页面置换算法 一、进度调度算法 常见的进度调度算法以及特点如下&#xff1a; 二、磁盘调度算法 一、先…

【大数据】初步认识StarRocks

StarRocks是什么 StarRocks 是新一代极速全场景 MPP 数据库。 StarRocks 充分吸收关系型 OLAP 数据库和分布式存储系统在大数据时代的优秀研究成果&#xff0c;在业界实践的基础上&#xff0c;进一步改进优化、升级架构&#xff0c;并增添了众多全新功能&#xff0c;形成了全新…

数据挖掘18大算法实现以及其他相关经典DM算法:决策分类,聚类,链接挖掘,关联挖掘,模式挖掘、图算法,搜索算法等

【机器学习入门与实践】入门必看系列&#xff0c;含数据挖掘项目实战&#xff1a;模型融合、特征优化、特征降维、探索性分析等&#xff0c;实战带你掌握机器学习数据挖掘 专栏详细介绍&#xff1a;【机器学习入门与实践】合集入门必看系列&#xff0c;含数据挖掘项目实战&…

TiDB(1):TiDB简介

1 从MySQL到TiDB 1.1 场景引入 假设现在有一个高速发展的互联网公司,核心业务库MySQL的数据量已经近亿行,且还在不断增长中,公司对于数据资产较为重视,所有数据要求多副本保存至少5年,且除了有对历史数据进行统计分析的离线报表业务外,还有一些针对用户数据实时查询的需求,如用…

软件测试技能,JMeter压力测试教程,签名sign(BeanShell 预处理程序)(二十)

前言 一般公司对外的接口都会用到sign签名&#xff0c;对不同的客户提供不同的apikey ,这样可以提高接口请求的安全性&#xff0c;避免被人抓包后乱请求 之前讲过用python代码实现sign签名&#xff0c;这次介绍jmeter上如何实现sign签名&#xff0c;思路都是差不多的 一、si…

Java框架之springboot基础

写在前面 本文看下springboot相关的基础内容。 1&#xff1a;从spring到springboot 在工作中&#xff0c;如果是我们想要引入某个框架&#xff0c;比如引入springMVC&#xff0c;就需要在web.xml中配置DispatcherServlet&#xff0c;在springmvc的配置文件中配置视图解析器等…

App自动化测试|Appium+Python自动化测试环境搭建

windows下搭建pythonappium环境 搭建过程步骤如下&#xff1a; 安装jdk并配置好环境变量&#xff08;jdk版本1.8以上&#xff09;安装android-sdk并配置好环境变量&#xff1b;具体步骤见&#xff1a;Android Studio安装(推荐使用这种方法安装SDK) - 环境配置 - 测试人社区安…

ASEMI代理海矽美SFP3012, 快恢复二极管SFP3012参数

编辑-Z SFP3012参数描述&#xff1a; 型号&#xff1a;SFP3012 最大反向重复峰值电压VRRM&#xff1a;1200V 平均整流正向电流IF&#xff1a;30A 反向恢复时间TRR&#xff1a;≤65nS 正向峰值浪涌电流IFSM&#xff1a;1602A 工作接点温度TJ&#xff1a;-40&#xff5e;1…

【数据挖掘】时间序列教程【七】

4.3 分布式滞后模型 考虑响应时间序列 y t 和输入(或“曝光”)时间序列 X t 。可能还有其他值得考虑的协变量,我们暂时忽略它们并在下一节中讨论它们的包含情况。我们将考虑以下形式的模型 在哪里 ε 表示独立同分布噪声过程。在连续时间设置中,该模型可以写为: …

VS上配置docker步骤记录

1:VS里安装Remote Development 2:运行 sudo usermod -aG docker $USER。#将当前用户添加到docker用户组中 sudo newgrp docker#更新,运行这个切到了root用户,获取权限 docker ps #列出正在运行的容器。它会显示容器的相关信息&#xff0c;如容器ID、镜像名称、创建时间、状态…

Linux 用户名称高亮和最近路径显示

1、通常情况下&#xff0c;Linux中的路径名称会不断叠加显示&#xff0c;如下图&#xff0c;这样看起来会很长。 2、为了设置路径只是当前最近的文件路径&#xff0c;先进入自己的家目录&#xff0c;然后进入.bashrc&#xff1a; 3、在.bashrc文件中的最后一行加入以下内容…

C# int[,] 和 int[,,]

如标题&#xff1b; 在C#中这两个是定义二维和三维数组的&#xff1b;这和C语言的写法不同&#xff1b; C语言定义二维数组是&#xff0c; int a[5][3]; 看下C#的多维数组&#xff1b;输出数组其中一个值&#xff1b; using System;class Program {static void Main(string[…

STM32 Proteus UCOSII系统拔河小游戏LED模拟-0053

STM32 Proteus UCOSII系统拔河小游戏LED模拟-0053 Proteus仿真小实验&#xff1a; STM32 Proteus UCOSII系统拔河小游戏LED模拟-0053 功能&#xff1a; 硬件组成&#xff1a;STM32F103R6单片机 1个选手1按键1个选手2按键1个重新开始按键7个LED灯1个蜂鸣器 1.单片机程序使用…

迷迷糊糊?似懂非懂?一文让你从此对SPI了如指掌

迷迷糊糊&#xff1f;似懂非懂&#xff1f;一文让你从此对SPI了如指掌 前言一、SPI 与 API1. SPI 在生活中的类比2. SPI 在代码上的例子3. API 与 SPI 的关系 二、JAVA 的 SPI 机制1. JAVA 中的 SPI 例子2. SPI 机制的四大组件3. SPI 机制的实现4. JAVA SPI的不足 前言 你是不…

CICD集合(四):Jenkins配置JDK,Maven,Allure报告

在Jenkins上面配置Jdk以及Maven环境 Maven和JDK Allure报告配置 当然配置Allure,得先安装Allure插件&#xff1a;

【Java项目】SpringBoot项目如何从自研配置中心拉取配置

文章目录 前言思路 前言 先简单说一下这个题目的意思是什么。 我们知道&#xff0c;如果我们的项目是SpringCloud的项目&#xff0c;我们是可以把我们的本地配置写到云端的的配置中心的&#xff0c;比如集成SpringCloud Alibaba&#xff0c;你就可以使用Nacos&#xff0c;然后…

科技云报道:智能化潮起,物联网产业链安全和效率问题何解?

科技云报道原创。 黑灯瞎火的夜。一胖一瘦两个小伙分别拿着平板和手机&#xff0c;在某知名新能源汽车周围鬼鬼祟祟地打转。 不到一分钟的时间&#xff0c;其中的瘦小伙很轻易地就用手机解开了车门锁。另外一名胖小伙&#xff0c;却用了两分钟&#xff0c;花了老大的力气&…

网站建设如何快速建站_网站建设快速建站有哪些方法

网站建设快速建站方法 1、JavaScript 压缩和模块打包 JavaScript 应用是以源码形式进行分发的&#xff0c;而源码解析的效率是要比字节码低的。对于一小段脚本来说&#xff0c;区别可以忽略不计。但是对于更大型的应用&#xff0c;脚本的大小会对应用启动时间有着负面的影响。…

dubbo Sentinet 限流 流控配置 高级 直连 关联 链路 预热冷启动 排队等待 单机 qps 并发 机器总体法制 单机均摊 集群俩种身份

目录 进入配置 单机超过10个限流 Qps 和 并发线程数区别使用思路 集群阈值模式 单机均摊 总体阈值 集群流控中共有两种身份&#xff1a; 高级-流控模式 直连 关联 链路 首先在实现类上加注解 Warm Up 预热冷启动 10秒内完成 100 预热并发效果 效果 排队等待 单…