【Java基础】Java Lambda表达式详解

news2024/10/1 23:36:30

Lambda 表达式,即函数式编程是 JDK8 的一个新特性,也被称为闭包,Lambda表达式允许把函数作为一个方法的参数,即行为参数化,函数作为参数传递进方法中。

Lambda表达式可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。

总结就是:使用不可变值与函数,函数对不可变值进行处理,映射成另一个值。


一、什么是函数式接口

函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型。使用@FunctionalInterface注解修饰的类,编译器会检测该类是否只有一个抽象方法或接口,否则,会报错。可以有多个默认方法,静态方法。

lambda 表达式是一小段代码,它接受参数并返回一个值。Lambda 表达式类似于方法,但它们不需要名称,并且可以直接在方法体中实现。

语法:最简单的 lambda 表达式包含一个参数和一个表达式:

  • 零参数:

() -> System.out.println("零参数 lambda");
  • 一个参数:

p -> System.out.println("一个参数:" + param);
  • 多个参数:

(p1 [,p2,p3,....pn]) -> System.out.println("多个参数:" + p1 + ", " + p2 + ... + pn);

上面的表达式有一定的限制。它们要么返回一个值要么执行一段方法,并且它们不能包含变量、赋值或语句,例如if or for 。为了进行更复杂的操作,可以使用带有花括号的代码块。如果 lambda 表达式需要返回一个值,那么代码块应该有一个return语句。


(parameter1, parameter2) -> { code block [return] }

1、方法引用

  • 类 :: 静态方法

Consumer<String> c = [ (s) -> System.out.println(s);  <=>  System.out::println; ]
  • 对象 :: 实例方法

List<String> list = Lists.newArrayList();
Consumer<String> c = [ (e) => list.add(e);  <=>  list::add; ]
  • 构造器 :: new

Supplier<List<String>> s = [ () -> new ArrayList<>(); <=> ArrayList::new; ]

2、@FunctionalInterface注解

有且只有一个抽象方法的接口被称为函数式接口,函数式接口适用于函数式编程的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象,一定要确保接口中有且只有一个抽象方法,这样Lambda才能顺利的进行推导。

与@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解:@FunctionalInterface 。该注解可用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法(equal和hashcode方法不算),否则将会报错。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。

3、 java8自带的常用函数式接口。

4、简单的例子

package com.biyu.study.lambda;

import com.biyu.study.lambda.bean.Employee;

import java.math.BigDecimal;
import java.util.function.*;

public class Test {
    public static void main(String[] args) {
        Predicate<Integer> predicate = x -> x > 20;
        Employee employee = new Employee("Lily", "女", 18);
        System.out.println("Lily的大于18岁吗?:" + predicate.test(employee.getAge()));

        Consumer<String> consumer = System.out::println;
        consumer.accept("Hello World");

        Function<Employee, String> function = Employee::getName;
        String name = function.apply(employee);
        System.out.println(name);

        Supplier<Integer> supplier = () -> Integer.valueOf(BigDecimal.TEN.toString());
        System.out.println(supplier.get());

        UnaryOperator<Boolean> unaryOperator = uglily -> !uglily;
        Boolean apply2 = unaryOperator.apply(true);
        System.out.println(apply2);

        BinaryOperator<Integer> operator = (x, y) -> x * y;
        Integer integer = operator.apply(2, 3);
        System.out.println(integer);

        test(() -> "函数式接口");
    }

    /**
     * 自定义函数式接口使用
     *
     * @param worker
     */
    public static void test(Worker worker) {
        String work = worker.work();
        System.out.println(work);
    }

    public interface Worker {
        String work();
    }
}

以上演示了lambda接口的使用及自定义一个函数式接口并使用。

二、Lambda 流的常用方法

1、ForEach

集合的遍历 forEach 方法:

public static void testForEach(){
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
        }};

        list.forEach(s-> System.out.println(s));
    }

2、Collect

将操作后的对象转化为新的对象:

public static void testCollect(){
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("2");
        }};

        //转换为新的list
        List newList = list.stream().map(s -> Integer.valueOf(s)).collect(Collectors.toList());
        System.out.println(newList);
    }

3、Filter

Filter 为过滤的意思,只要满足 Filter 表达式的数据就可以留下来,不满足的数据被过滤掉。

public static void testFilter() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
        }};

        List<String> filtered = list.stream()
                // 过滤掉我们希望留下来的值
                // 表示我们希望字符串是 1 能留下来
                // 其他的过滤掉
                .filter(str -> "1".equals(str))
                .collect(Collectors.toList());
        System.out.println(filtered);
    }

4、Map

map 方法可以让我们进行一些流的转化,比如原来流中的元素是 A,通过 map 操作,可以使返回的流中的元素是 B。

public static void testMap() {
        List<String> list = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
        }};
        //通过 map 方法list中元素转化成 小写
        List<String> strLowerList = list.stream()
                .map(str -> str.toLowerCase())
                .collect(Collectors.toList());
        System.out.println(strLowerList);
    }

5、MapToInt

mapToInt 方法的功能和 map 方法一样,只不过 mapToInt 返回的结果已经没有泛型,已经明确是 int 类型的流了。

public static void testMapToInt() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
        }};
        List<Integer> intList=list.stream()
                .mapToInt(s->Integer.valueOf(s))
                // 一定要有 mapToObj,因为 mapToInt 返回的是 IntStream,因为已经确定是 int 类型了,所以没有泛型的,
                // 而 Collectors.toList() 强制要求有泛型的流,所以需要使用 mapToObj方法返回有泛型的流
                .mapToObj(s->s)
                .collect(Collectors.toList());
        System.out.println(intList);
        Double sum = list.stream()
                .mapToDouble(s->Double.valueOf(s))
                // DoubleStream/IntStream 有许多 sum(求和)、min(求最小值)、max(求最大值)、average(求平均值)等方法
                .sum();
        System.out.println(sum);
    }

6、Distinct

distinct 方法有去重的功能:

public static void testDistinct() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("2");
            add("5");
            add("3");
        }};
        List<Integer> intList = list.stream()
                .map(s -> Integer.valueOf(s))
                .distinct()
                .collect(Collectors.toList());
        System.out.println(intList);
    }

7、Sorted

Sorted 方法提供了排序的功能,并且允许我们自定义排序。

public static void testSorted() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("-1");
            add("9");
            add("11");
            add("27");
            add("0");
        }};
        List<Integer> intList = list.stream()
                .map(s -> Integer.valueOf(s))
                // 等同于 .sorted(Comparator.naturalOrder()) 自然排序
                .sorted()
                .collect(Collectors.toList());
        System.out.println(intList);
        // 自定义排序器
        intList =list.stream()
                .map(s -> Integer.valueOf(s))
                // 反自然排序
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList());
        System.out.println(intList);
    }

8、groupingBy

groupingBy 是能够根据字段进行分组,toMap 是把 List 的数据格式转化成 Map 的格式。

public static void testGroupBy() {
        List<String> list = new ArrayList<String>() {{
            add("iphone 4s");
            add("iphone 6");
            add("iphone 12");
            add("iphone 14");
            add("xiaomi");
            add("huawei");
            add("oppo");
        }};

        Map<String, List<String>> strList = list.stream().collect(Collectors.groupingBy(s -> {

            if (s.startsWith("iphone")){
                return "iphone";
            } else {
                return "other";
            }
        }));
        System.out.println(strList);
    }

9、FindFirst

findFirst 表示匹配到第一个满足条件的值就返回:

public static void testFindFirst() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("2");
        }};

        list.stream()
                .filter(s -> "2".equals(s))
                .findFirst()
                .get();

        // 防止空指针
        list.stream()
                .filter(s -> "2".equals(s))
                .findFirst()
                // orElse 表示如果 findFirst 返回 null 的话,就返回 orElse 里的内容
                .orElse("3");

        Optional<String> str = list.stream()
                .filter(s -> "2".equals(s))
                .findFirst();
        // isPresent 为 true 的话,表示 value != null
        if (str.isPresent()) {
            return;
        }
    }

10、Reduce

reduce 方法允许我们在循环里面叠加计算值:

public static void testReduce() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
        }};

        int sum = list.stream()
                .map(s -> Integer.valueOf(s))
                // s1 和 s2 表示循环中的前后两个数
                .reduce((s1, s2) -> s1 + s2)
                .orElse(0);
        System.out.println(sum);
        sum =list.stream()
                .map(s -> Integer.valueOf(s))
                // 第一个参数表示基数,会从 100 开始加
                .reduce(100, (s1, s2) -> s1 + s2);
        System.out.println(sum);
    }

11、Peek

peek 方法很简单,我们在 peek 方法里面做任意没有返回值的事情,比如打印日志:

public static void testPeek() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
        }};
        list.stream().map(s -> Integer.valueOf(s))
                .peek(s -> System.out.println(s))
                .collect(Collectors.toList());
    }

12、Limit

limit 方法会限制输出值个数,入参是限制的个数大小:

public static void testLimit() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
            add("3");
            add("4");
            add("5");
        }};
       List<Integer> integers= list.stream()
                .map(s -> Integer.valueOf(s))
                .limit(3L)
                .collect(Collectors.toList());
        System.out.println(integers);

    }

13、Max,Min

通过 max、min 方法,可以获取集合中最大、最小的对象。

public static void testMaxMin() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("3");
            add("2");
            add("-12");
            add("99");
        }};

        String maxNum = list.stream().max(Comparator.comparing(s -> Integer.valueOf(s))).get();
        String minNum = list.stream().min(Comparator.comparing(s -> Integer.valueOf(s))).get();
        System.out.println(maxNum);
        System.out.println(minNum);
    }

三、写在最后

本章节主要从实际使用讲述了常用的方法及流,文中例子主要是为了讲解较为简单,大家可以去使用java8重构自己现有的代码,自行领会lambda的奥妙使用。java8可以很清晰表达你要做什么,代码也很简洁。

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

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

相关文章

前端开发规范,你真的了解吗?一起来学习一下前端开发规范,让你的代码高级起来!

代码规范 1 编码风格规范 1.1 使用ES6风格编码源码 定义变量使用let ,定义常量使用const 使用export &#xff0c;import 模块化 1.2 组件 props 原子化 提供默认值 使用 type 属性校验类型 使用 props 之前先检查该 prop 是否存在 1.3 避免 this.$parent 1.4 谨慎使用 …

文献阅读(46)——MPViT

文献阅读&#xff08;46&#xff09;——MPViT 文章目录文献阅读&#xff08;46&#xff09;——MPViTMPViT先验知识/知识拓展文章结构文章结果1. ImageNet 分类2. 物体检测和实例分割3. 语义分割方法1. MPViT architecture2. MS-Patch Embed Block3. MP-Transformer Block ![在…

【超级超级无敌好用的三个实用网站,用完就走,尽显渣男本色】

今天我来给大家分享超级超级无敌好用的三个实用网站&#xff0c;用完就走&#xff0c;尽显渣男本色&#xff0c;如果你觉得有帮助&#xff0c;点了赞吧&#xff0c;创作不易&#xff0c;关注再走&#xff0c;后续更精彩。 一. tinywow 首先我们推荐的是国外一款在线实用网站工…

面试题CSS篇(一)

目录 一、flex布局 1、基本概念 2、容器属性 &#xff08;1&#xff09;flex-direction 决定主轴的方向&#xff08;即项目的排列方向&#xff09; &#xff08;2&#xff09; flex-wrap &#xff08;3&#xff09;flex-flow &#xff08;4&#xff09;justify-content…

【ECNU】3633. 双人旋转赛车(C++)

目录 题目 输入格式 输出格式 样例 提示 思路 代码 题目 单点时限: 2.0 sec 内存限制: 1024 MB oxx 和 Xiejiadong 在玩一个双人旋转赛车的小游戏。 他们将进行一些比赛。每局比赛必须按顺序进行&#xff0c;胜者会得到该局对应的分数 xi。 由于 oxx 技艺不精&#…

PMP®考试抽中审查提供的材料

PMP审查流程&#xff1a;属于第一类的申请者&#xff08;学士学位或同等学位及以上&#xff09;1&#xff0e; 核实学士学位或同等学位2&#xff0e; 核实项目管理经验3&#xff0e; 核实35小时的项目管理教育属于第二类的申请者&#xff08;高中、大专或同等学历&#xff09;1…

解决httprunner3.x上$符号无法当成普通符号用的方法

前言 由于要测试的api中会涉及$符号的传递, 要求其放在参数中当一个普通符号使用, 但由于httprunner框架处理逻辑, 会将如$coe当成一个变量, 从而报错找不到该变量的值 现象 接口某参数为: coeConfig$coal$08d99cca03a84d1d9e9a49b4534bb598运行时框架会抛出异常: 分析 研读框…

iphone系统崩溃数据能恢复吗?教你三招方法

最近有些苹果用户反应自己手机的屏幕无法滑动&#xff0c;桌面上APP也无法点开&#xff0c;想要关机重启下试试&#xff0c;可是&#xff0c;连关机都关不了&#xff0c;甚至连Siri都罢工了。苹果手机系统崩溃&#xff0c;出现黑屏、白屏、无限重启之类的故障&#xff0c;导致手…

rtthread 线程

创建动态线程最简单代码 #include <rtthread.h>//包含头文件static rt_thread_t thread1 RT_NULL; //创建线程控制块指针&#xff0c;指向空static void thread1_entry(void *parameter)//线程入口&#xff08;干什么&#xff09; {rt_kprintf("do something"…

ChatGPT 爆火,社交应用如何 Get 新技能

风浪越大&#xff0c;鱼越贵。关注【融云全球互联网通信云】了解更多 现在&#xff0c;最大的浪无疑属于 ChatGPT&#xff0c;一款以对话方式进行交互的语言模型。 通过创新业务打下江山的商业传奇们&#xff0c;都怕跟丢了这波浪潮而成为“上一代人”。所以&#xff0c;我们…

[文件操作] File 类的用法和 InputStream, OutputStream 的用法

能吃是不是件幸福的事呢 文章目录前言1. 文件的相关定义2. 文件类型3. Java对文件系统的操作3.1 对文件的基础操作3.2 读文件3.3 写文件前言 从这章开始,我们就开始学文件操作相关的知识了~ 1. 文件的相关定义 1.文件的定义可以从狭义和广义两个方面解释. 狭义: 指硬盘上的文…

Redis学习笔记:缓存运用常见问题

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育 目录1、数据一致性的问题1.1、新增数据一致性的问题1.2、修改/删除一致性问题1.2.1、操作分析1.2.1、总结和再深入2、缓存穿透&#xff0c;缓存击穿和缓存雪崩2.1、缓存穿透&#xff08;查不到&#xff09;2.1.1、…

从功能到自动化,熬夜3天整理出这一份2000字学习指南~

学习自动化这个想法&#xff0c;其实自己在心里已经琢磨了很久&#xff0c;就是一直没付诸实践&#xff0c;觉得现在手工测试已经能满足当前的工作需要&#xff0c;不想浪费时间去学习新的东西&#xff0c;有点时间还不如刷刷视频、看看小说等。 第一次有学习Selenium的冲动是…

【Bio】碳水化合物 carbohydrate 和糖蛋白 glycoprotein

文章目录碳水化合物 carbohydrate单糖 monosaccharides戊糖 pentose己糖 hexose双糖 disaccharide寡糖 oligosaccharide 和多糖 polysaccharide糖蛋白 glycoproteinRef碳水化合物 carbohydrate 碳水化合物 (carbohydrate)&#xff0c;也是糖类&#xff0c;指的是一系列多羟基 …

pwnlab通关流程

pwnlab通关 关于文件包含&#xff0c;环境变量劫持的一个靶场 信息收集 靶机ip&#xff1a;192.168.112.133 开放端口 根据开放的端口信息决定从80web端口入手 目录信息 在images和upload路径存在目录遍历&#xff0c;config.php被渲染无法查看&#xff0c;upload.php需…

C++实现文本界面英语词典

C实现文本界面英语词典 C实现文本界面的英语词典&#xff0c;能在Dev-C运行。提供两种方案&#xff1a;一是简单仅查词功能&#xff1b;二是具有查词、添加、删除功能&#xff0c;具有选择菜单&#xff0c;值得一提的是&#xff0c;本程序对用户输入菜单选项序号做了检测&#…

Zabbix“专家坐诊”第183期问答汇总

问题一 Q&#xff1a;老师&#xff0c;请问一下zabbix采集的数据怎么过滤&#xff0c;获取数据是nottime20:30 notafter3&#xff0c;怎么过滤出netafter3 &#xff1f;谢谢。 A&#xff1a;过滤器设置如下图。 问题二 Q&#xff1a;大佬&#xff0c;请问一下被管节点部署了…

视觉Slam十四讲笔记

视觉SLAM十四讲 ch1~2 虚拟机部分指令解析在其他文件中进行引用该库编译器参考链接&#xff1a;虚拟机部分 CMakeList.txt文件是cmake用来生成Makefile文件需要的一个描述编译链接的规则文件 指令解析 &#xff08;1&#xff09;PROJECT(projectname [CXX] [C] [Java]): 该…

力扣(LeetCode)427. 建立四叉树(2023.03.01)

给你一个 n * n 矩阵 grid &#xff0c;矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。 你需要返回能表示矩阵的 四叉树 的根结点。 注意&#xff0c;当 isLeaf 为 False 时&#xff0c;你可以把 True 或者 False 赋值给节点&#xff0c;两种值都会被判题机制 接受…

Elasticsearch进阶之(核心概念、系统架构、路由计算、倒排索引、分词、Kibana)

Elasticsearch进阶之&#xff08;核心概念、系统架构、路由计算、倒排索引、分词、Kibana&#xff09; 1、核心概念&#xff1a; 1.1、索引&#xff08;Index&#xff09; 一个索引就是一个拥有几分相似特征的文档的集合。比如说&#xff0c;你可以有一个客户数据的索引&…